From b9e138939b1140f2ebca59d7efaa625ac19f8aed Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 3 May 2024 15:20:59 +0200 Subject: [PATCH 001/226] refactor, add feature for register address --- dlt-connector/src/data/User.repository.ts | 8 +++ .../src/data/proto/3_3/RegisterAddress.ts | 20 ++++++ .../src/data/proto/3_3/TransactionBody.ts | 15 ++++- .../src/data/proto/TransactionBody.builder.ts | 11 +++- .../src/data/proto/transactionBody.logic.ts | 59 +++++++++++++++++ .../src/graphql/resolver/AccountsResolver.ts | 60 ++++++++++++++++++ .../graphql/resolver/TransactionsResolver.ts | 2 +- .../account/RegisterAddress.context.ts | 63 +++++++++++++++++++ .../community/HomeCommunity.role.ts | 6 +- .../AbstractTransactionRecipeRole.ts | 15 +++++ ...> BalanceChangingTransactionRecipeRole.ts} | 17 +---- .../CommunityRootTransaction.role.ts | 8 +-- .../CreateTransactionRecipe.context.test.ts | 2 +- ....ts => CreateTransactionRecipe.context.ts} | 38 ++++++++--- .../RegisterAddressTransaction.role.ts | 29 +++++++++ .../TransmitToIota.context.test.ts | 2 +- 16 files changed, 318 insertions(+), 37 deletions(-) create mode 100644 dlt-connector/src/data/proto/transactionBody.logic.ts create mode 100644 dlt-connector/src/graphql/resolver/AccountsResolver.ts create mode 100644 dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts create mode 100644 dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts rename dlt-connector/src/interactions/backendToDb/transaction/{TransactionRecipe.role.ts => BalanceChangingTransactionRecipeRole.ts} (87%) rename dlt-connector/src/interactions/backendToDb/transaction/{CreateTransationRecipe.context.ts => CreateTransactionRecipe.context.ts} (61%) create mode 100644 dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts diff --git a/dlt-connector/src/data/User.repository.ts b/dlt-connector/src/data/User.repository.ts index 6e5a66203..1e9e4dcef 100644 --- a/dlt-connector/src/data/User.repository.ts +++ b/dlt-connector/src/data/User.repository.ts @@ -1,5 +1,6 @@ import { Account } from '@entity/Account' import { User } from '@entity/User' +import { FindOptionsRelations } from 'typeorm' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { getDataSource } from '@/typeorm/DataSource' @@ -21,4 +22,11 @@ export const UserRepository = getDataSource() return account } }, + + findByGradidoId( + { uuid }: UserIdentifier, + relations?: FindOptionsRelations, + ): Promise { + return User.findOne({ where: { gradidoID: uuid }, relations }) + }, }) diff --git a/dlt-connector/src/data/proto/3_3/RegisterAddress.ts b/dlt-connector/src/data/proto/3_3/RegisterAddress.ts index 87f09afbd..08cb39868 100644 --- a/dlt-connector/src/data/proto/3_3/RegisterAddress.ts +++ b/dlt-connector/src/data/proto/3_3/RegisterAddress.ts @@ -1,15 +1,35 @@ /* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/no-unused-vars */ +import { Account } from '@entity/Account' import { Transaction } from '@entity/Transaction' +import { User } from '@entity/User' import { Field, Message } from 'protobufjs' import { AddressType } from '@/data/proto/3_3/enum/AddressType' +import { AccountType } from '@/graphql/enum/AccountType' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { accountTypeToAddressType } from '@/utils/typeConverter' import { AbstractTransaction } from '../AbstractTransaction' // https://www.npmjs.com/package/@apollo/protobufjs // eslint-disable-next-line no-use-before-define export class RegisterAddress extends Message implements AbstractTransaction { + constructor(transaction?: UserAccountDraft, account?: Account) { + if (transaction) { + super({ addressType: accountTypeToAddressType(transaction.accountType) }) + if (account) { + this.derivationIndex = account.derivationIndex + this.accountPubkey = account.derive2Pubkey + if (account.user) { + this.userPubkey = account.user.derive1Pubkey + } + } + } else { + super() + } + } + @Field.d(1, 'bytes') public userPubkey: Buffer diff --git a/dlt-connector/src/data/proto/3_3/TransactionBody.ts b/dlt-connector/src/data/proto/3_3/TransactionBody.ts index 39d5602ec..934e05cfc 100644 --- a/dlt-connector/src/data/proto/3_3/TransactionBody.ts +++ b/dlt-connector/src/data/proto/3_3/TransactionBody.ts @@ -4,12 +4,14 @@ import { Field, Message, OneOf } from 'protobufjs' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { TransactionError } from '@/graphql/model/TransactionError' import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' import { timestampToDate } from '@/utils/typeConverter' import { AbstractTransaction } from '../AbstractTransaction' +import { determineCrossGroupType, determineOtherGroup } from '../transactionBody.logic' import { CommunityRoot } from './CommunityRoot' import { PROTO_TRANSACTION_BODY_VERSION_NUMBER } from './const' @@ -25,14 +27,21 @@ import { Timestamp } from './Timestamp' // https://www.npmjs.com/package/@apollo/protobufjs // eslint-disable-next-line no-use-before-define export class TransactionBody extends Message { - public constructor(transaction?: TransactionDraft | CommunityDraft) { + public constructor(transaction?: TransactionDraft | CommunityDraft | UserAccountDraft) { if (transaction) { + let type = CrossGroupType.LOCAL + let otherGroup = '' + if (transaction instanceof TransactionDraft) { + type = determineCrossGroupType(transaction) + otherGroup = determineOtherGroup(type, transaction) + } + super({ memo: 'Not implemented yet', createdAt: new Timestamp(new Date(transaction.createdAt)), versionNumber: PROTO_TRANSACTION_BODY_VERSION_NUMBER, - type: CrossGroupType.LOCAL, - otherGroup: '', + type, + otherGroup, }) } else { super() diff --git a/dlt-connector/src/data/proto/TransactionBody.builder.ts b/dlt-connector/src/data/proto/TransactionBody.builder.ts index 22d943d48..cfc1e808b 100644 --- a/dlt-connector/src/data/proto/TransactionBody.builder.ts +++ b/dlt-connector/src/data/proto/TransactionBody.builder.ts @@ -4,12 +4,14 @@ import { Community } from '@entity/Community' import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { LogError } from '@/server/LogError' import { CommunityRoot } from './3_3/CommunityRoot' import { CrossGroupType } from './3_3/enum/CrossGroupType' import { GradidoCreation } from './3_3/GradidoCreation' import { GradidoTransfer } from './3_3/GradidoTransfer' +import { RegisterAddress } from './3_3/RegisterAddress' import { TransactionBody } from './3_3/TransactionBody' export class TransactionBodyBuilder { @@ -99,9 +101,16 @@ export class TransactionBodyBuilder { return this } + public fromUserAccountDraft(userAccountDraft: UserAccountDraft, account: Account): this { + this.body = new TransactionBody(userAccountDraft) + this.body.registerAddress = new RegisterAddress(userAccountDraft, account) + this.body.data = 'registerAddress' + return this + } + public fromTransactionDraft(transactionDraft: TransactionDraft): TransactionBodyBuilder { this.body = new TransactionBody(transactionDraft) - // TODO: load pubkeys for sender and recipient user from db + // TODO: load public keys for sender and recipient user from db switch (transactionDraft.type) { case InputTransactionType.CREATION: if (!this.recipientAccount) { diff --git a/dlt-connector/src/data/proto/transactionBody.logic.ts b/dlt-connector/src/data/proto/transactionBody.logic.ts new file mode 100644 index 000000000..69d7e565e --- /dev/null +++ b/dlt-connector/src/data/proto/transactionBody.logic.ts @@ -0,0 +1,59 @@ +import { InputTransactionType } from '@/graphql/enum/InputTransactionType' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { TransactionError } from '@/graphql/model/TransactionError' + +import { CrossGroupType } from './3_3/enum/CrossGroupType' + +export const determineCrossGroupType = ({ + user, + linkedUser, + type, +}: TransactionDraft): CrossGroupType => { + if ( + !linkedUser.communityUuid || + !user.communityUuid || + linkedUser.communityUuid === '' || + user.communityUuid === '' || + user.communityUuid === linkedUser.communityUuid || + type === InputTransactionType.CREATION + ) { + return CrossGroupType.LOCAL + } else if (type === InputTransactionType.SEND) { + return CrossGroupType.INBOUND + } else if (type === InputTransactionType.RECEIVE) { + return CrossGroupType.OUTBOUND + } + throw new TransactionError( + TransactionErrorType.NOT_IMPLEMENTED_YET, + 'cannot determine CrossGroupType', + ) +} + +export const determineOtherGroup = ( + type: CrossGroupType, + { user, linkedUser }: TransactionDraft, +): string => { + switch (type) { + case CrossGroupType.LOCAL: + return '' + case CrossGroupType.INBOUND: + if (!linkedUser.communityUuid || linkedUser.communityUuid === '') { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'missing linkedUser community id for cross group transaction', + ) + } + return linkedUser.communityUuid + case CrossGroupType.OUTBOUND: + if (!user.communityUuid || user.communityUuid === '') { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'missing user community id for cross group transaction', + ) + } + return user.communityUuid + case CrossGroupType.CROSS: + throw new TransactionError(TransactionErrorType.NOT_IMPLEMENTED_YET, 'not implemented yet') + } +} diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts new file mode 100644 index 000000000..91ac7bd73 --- /dev/null +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -0,0 +1,60 @@ +import { Arg, Mutation, Query, Resolver } from 'type-graphql' +import { QueryFailedError } from 'typeorm' + +import { TransactionRecipe } from '@model/TransactionRecipe' + +import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' +import { UserRepository } from '@/data/User.repository' +import { RegisterAddressContext } from '@/interactions/backendToDb/account/RegisterAddress.context' +import { logger } from '@/logging/logger' +import { TransactionLoggingView } from '@/logging/TransactionLogging.view' +import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' +import { getDataSource } from '@/typeorm/DataSource' + +import { TransactionErrorType } from '../enum/TransactionErrorType' +import { UserAccountDraft } from '../input/UserAccountDraft' +import { UserIdentifier } from '../input/UserIdentifier' +import { TransactionError } from '../model/TransactionError' +import { TransactionResult } from '../model/TransactionResult' + +@Resolver() +export class AccountResolver { + @Query(() => Boolean) + async isAccountExist(@Arg('data') userIdentifier: UserIdentifier): Promise { + logger.info('isAccountExist', userIdentifier) + return !!(await UserRepository.findAccountByUserIdentifier(userIdentifier)) + } + + @Mutation(() => TransactionResult) + async registerAddress( + @Arg('data') + userAccountDraft: UserAccountDraft, + ): Promise { + const registerAddressContext = new RegisterAddressContext(userAccountDraft) + try { + const { transaction, account } = await registerAddressContext.run() + await getDataSource().transaction(async (transactionalEntityManager) => { + await transactionalEntityManager.save(account) + await transactionalEntityManager.save(transaction) + logger.debug('store register address transaction', new TransactionLoggingView(transaction)) + }) + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) + return new TransactionResult(new TransactionRecipe(transaction)) + } catch (err) { + if (err instanceof QueryFailedError) { + logger.error('error saving user or new account or transaction into db: %s', err) + return new TransactionResult( + new TransactionError( + TransactionErrorType.DB_ERROR, + 'error saving user or new account or transaction into db', + ), + ) + } else if (err instanceof TransactionError) { + return new TransactionResult(err) + } else { + logger.error('error in register address: ', err) + throw err + } + } + } +} diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 7cc619400..3f34584a9 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -4,7 +4,7 @@ import { TransactionDraft } from '@input/TransactionDraft' import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' import { TransactionRepository } from '@/data/Transaction.repository' -import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransationRecipe.context' +import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransactionRecipe.context' import { BackendTransactionLoggingView } from '@/logging/BackendTransactionLogging.view' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' diff --git a/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts b/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts new file mode 100644 index 000000000..196c0daf4 --- /dev/null +++ b/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts @@ -0,0 +1,63 @@ +import { Account } from '@entity/Account' +import { Transaction } from '@entity/Transaction' +import { User } from '@entity/User' + +import { AccountFactory } from '@/data/Account.factory' +import { CommunityRepository } from '@/data/Community.repository' +import { KeyPair } from '@/data/KeyPair' +import { UserFactory } from '@/data/User.factory' +import { UserLogic } from '@/data/User.logic' +import { UserRepository } from '@/data/User.repository' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { TransactionError } from '@/graphql/model/TransactionError' +import { logger } from '@/logging/logger' + +import { CreateTransactionRecipeContext } from '../transaction/CreateTransactionRecipe.context' + +export interface TransactionWithAccount { + transaction: Transaction + account: Account +} + +export class RegisterAddressContext { + // eslint-disable-next-line no-useless-constructor + public constructor(private userAccountDraft: UserAccountDraft) {} + + public async run(): Promise { + const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() + const user = await this.loadOrCreateUser(communityKeyPair) + if (this.isAccountAlreadyExistOnUser(user)) { + throw new TransactionError( + TransactionErrorType.ALREADY_EXIST, + 'account for this user already exist!', + ) + } + logger.info('add user and account', this.userAccountDraft) + const account = this.createAccount(new UserLogic(user).calculateKeyPair(communityKeyPair)) + account.user = user + const createTransactionContext = new CreateTransactionRecipeContext(this.userAccountDraft, { + account, + }) + await createTransactionContext.run() + return { transaction: createTransactionContext.getTransactionRecipe(), account } + } + + public isAccountAlreadyExistOnUser(user: User): boolean { + return !!user.accounts?.find( + (value) => value.derivationIndex === this.userAccountDraft.user.accountNr, + ) + } + + public async loadOrCreateUser(communityKeyPair: KeyPair): Promise { + let user = await UserRepository.findByGradidoId(this.userAccountDraft.user, { accounts: true }) + if (!user) { + user = UserFactory.create(this.userAccountDraft, communityKeyPair) + } + return user + } + + public createAccount(userKeyPair: KeyPair): Account { + return AccountFactory.createAccountFromUserAccountDraft(this.userAccountDraft, userKeyPair) + } +} diff --git a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts index 5d7bec94c..ad259b372 100644 --- a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts +++ b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts @@ -15,7 +15,7 @@ import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' import { LogError } from '@/server/LogError' import { getDataSource } from '@/typeorm/DataSource' -import { CreateTransactionRecipeContext } from '../transaction/CreateTransationRecipe.context' +import { CreateTransactionRecipeContext } from '../transaction/CreateTransactionRecipe.context' import { CommunityRole } from './Community.role' @@ -44,7 +44,9 @@ export class HomeCommunityRole extends CommunityRole { this.self.aufAccount = AccountFactory.createAufAccount(keyPair, this.self.createdAt) this.self.gmwAccount = AccountFactory.createGmwAccount(keyPair, this.self.createdAt) - const transactionRecipeContext = new CreateTransactionRecipeContext(communityDraft, this.self) + const transactionRecipeContext = new CreateTransactionRecipeContext(communityDraft, { + community: this.self, + }) await transactionRecipeContext.run() this.transactionRecipe = transactionRecipeContext.getTransactionRecipe() } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts new file mode 100644 index 000000000..812f6a7f0 --- /dev/null +++ b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts @@ -0,0 +1,15 @@ +import { Transaction } from '@entity/Transaction' + +import { TransactionBuilder } from '@/data/Transaction.builder' + +export class AbstractTransactionRecipeRole { + protected transactionBuilder: TransactionBuilder + + public constructor() { + this.transactionBuilder = new TransactionBuilder() + } + + public getTransaction(): Transaction { + return this.transactionBuilder.getTransaction() + } +} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/TransactionRecipe.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts similarity index 87% rename from dlt-connector/src/interactions/backendToDb/transaction/TransactionRecipe.role.ts rename to dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts index f1be50c75..a4145cd44 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/TransactionRecipe.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts @@ -1,29 +1,22 @@ import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' import { AccountLogic } from '@/data/Account.logic' import { KeyPair } from '@/data/KeyPair' import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' -import { TransactionBuilder } from '@/data/Transaction.builder' import { UserRepository } from '@/data/User.repository' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { TransactionError } from '@/graphql/model/TransactionError' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' -export class TransactionRecipeRole { - protected transactionBuilder: TransactionBuilder - - public constructor() { - this.transactionBuilder = new TransactionBuilder() - } - +export class BalanceChangingTransactionRecipeRole extends AbstractTransactionRecipeRole { public async create( transactionDraft: TransactionDraft, transactionTypeRole: AbstractTransactionRole, - ): Promise { + ): Promise { const signingUser = transactionTypeRole.getSigningUser() const recipientUser = transactionTypeRole.getRecipientUser() @@ -82,8 +75,4 @@ export class TransactionRecipeRole { } return this.transactionBuilder.getCommunity() } - - public getTransaction(): Transaction { - return this.transactionBuilder.getTransaction() - } } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts index 75b885f2f..34d56cce0 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts @@ -4,13 +4,13 @@ import { KeyPair } from '@/data/KeyPair' import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionRecipeRole } from './TransactionRecipe.role' +import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' -export class CommunityRootTransactionRole extends TransactionRecipeRole { - public createFromCommunityRoot( +export class CommunityRootTransactionRole extends AbstractTransactionRecipeRole { + public create( communityDraft: CommunityDraft, community: Community, - ): CommunityRootTransactionRole { + ): AbstractTransactionRecipeRole { // create proto transaction body const transactionBody = new TransactionBodyBuilder() .fromCommunityDraft(communityDraft, community) diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts index e5535f3f7..117645bd1 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts @@ -15,7 +15,7 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' -import { CreateTransactionRecipeContext } from './CreateTransationRecipe.context' +import { CreateTransactionRecipeContext } from './CreateTransactionRecipe.context' // eslint-disable-next-line import/order import { communitySeed } from '@test/seeding/Community.seed' diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransationRecipe.context.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts similarity index 61% rename from dlt-connector/src/interactions/backendToDb/transaction/CreateTransationRecipe.context.ts rename to dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts index 8fa3dc443..42e633a18 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransationRecipe.context.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts @@ -1,3 +1,4 @@ +import { Account } from '@entity/Account' import { Community } from '@entity/Community' import { Transaction } from '@entity/Transaction' @@ -5,30 +6,38 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { TransactionError } from '@/graphql/model/TransactionError' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' +import { BalanceChangingTransactionRecipeRole } from './BalanceChangingTransactionRecipeRole' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' import { ReceiveTransactionRole } from './ReceiveTransaction.role' +import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { SendTransactionRole } from './SendTransaction.role' -import { TransactionRecipeRole } from './TransactionRecipe.role' /** * @DCI-Context * Context for create and add Transaction Recipe to DB */ +export interface AdditionalData { + community?: Community + account?: Account +} + export class CreateTransactionRecipeContext { - private transactionRecipeRole: TransactionRecipeRole + private transactionRecipe: AbstractTransactionRecipeRole // eslint-disable-next-line no-useless-constructor public constructor( - private draft: CommunityDraft | TransactionDraft, - private community?: Community, + private draft: CommunityDraft | TransactionDraft | UserAccountDraft, + private data?: AdditionalData, ) {} public getTransactionRecipe(): Transaction { - return this.transactionRecipeRole.getTransaction() + return this.transactionRecipe.getTransaction() } /** @@ -36,7 +45,7 @@ export class CreateTransactionRecipeContext { */ public async run(): Promise { if (this.draft instanceof TransactionDraft) { - this.transactionRecipeRole = new TransactionRecipeRole() + const transactionRecipeRole = new BalanceChangingTransactionRecipeRole() // contain logic for translation from backend to dlt-connector format let transactionTypeRole: AbstractTransactionRole switch (this.draft.type) { @@ -50,15 +59,24 @@ export class CreateTransactionRecipeContext { transactionTypeRole = new ReceiveTransactionRole(this.draft) break } - await this.transactionRecipeRole.create(this.draft, transactionTypeRole) + await transactionRecipeRole.create(this.draft, transactionTypeRole) return true } else if (this.draft instanceof CommunityDraft) { - if (!this.community) { + if (!this.data?.community) { throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community was not set') } - this.transactionRecipeRole = new CommunityRootTransactionRole().createFromCommunityRoot( + this.transactionRecipe = new CommunityRootTransactionRole().create( this.draft, - this.community, + this.data.community, + ) + return true + } else if (this.draft instanceof UserAccountDraft) { + if (!this.data?.account) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'account was not set') + } + this.transactionRecipe = await new RegisterAddressTransactionRole().create( + this.draft, + this.data.account, ) return true } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts new file mode 100644 index 000000000..84de6b5df --- /dev/null +++ b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts @@ -0,0 +1,29 @@ +import { Account } from '@entity/Account' + +import { AccountLogic } from '@/data/Account.logic' +import { CommunityRepository } from '@/data/Community.repository' +import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { TransactionError } from '@/graphql/model/TransactionError' + +import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' + +export class RegisterAddressTransactionRole extends AbstractTransactionRecipeRole { + async create( + userAccountDraft: UserAccountDraft, + account: Account, + ): Promise { + const bodyBuilder = new TransactionBodyBuilder() + const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() + const signingKeyPair = new AccountLogic(account).calculateKeyPair(communityKeyPair) + if (!signingKeyPair) { + throw new TransactionError(TransactionErrorType.NOT_FOUND, "couldn't found signing key pair") + } + this.transactionBuilder + .fromTransactionBodyBuilder(bodyBuilder.fromUserAccountDraft(userAccountDraft, account)) + .setSignature(signingKeyPair.sign(this.transactionBuilder.getTransaction().bodyBytes)) + .setSigningAccount(account) + return this + } +} diff --git a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts index 94a8e4f9d..520c4e143 100644 --- a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts +++ b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts @@ -14,7 +14,7 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { logger } from '@/logging/logger' -import { CreateTransactionRecipeContext } from '../backendToDb/transaction/CreateTransationRecipe.context' +import { CreateTransactionRecipeContext } from '../backendToDb/transaction/CreateTransactionRecipe.context' import { TransmitToIotaContext } from './TransmitToIota.context' From e4dcd7f0ce8b658b8ca163eb1f1c9a30384dc35a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 14 May 2024 11:55:21 +0200 Subject: [PATCH 002/226] add register address code to backend --- .../apis/dltConnector/DltConnectorClient.ts | 64 ++++++++++++++++++- .../src/apis/dltConnector/enum/AccountType.ts | 9 +++ .../dltConnector/model/UserAccountDraft.ts | 9 +++ backend/src/graphql/resolver/UserResolver.ts | 7 ++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 backend/src/apis/dltConnector/enum/AccountType.ts create mode 100644 backend/src/apis/dltConnector/model/UserAccountDraft.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 765d09fb4..4cdbffddf 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,4 +1,5 @@ import { Transaction as DbTransaction } from '@entity/Transaction' +import { User } from '@entity/User' import { gql, GraphQLClient } from 'graphql-request' import { CONFIG } from '@/config' @@ -6,13 +7,31 @@ import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' +import { AccountType } from './enum/AccountType' import { TransactionResult } from './model/TransactionResult' +import { UserAccountDraft } from './model/UserAccountDraft' import { UserIdentifier } from './model/UserIdentifier' const sendTransaction = gql` mutation ($input: TransactionInput!) { sendTransaction(data: $input) { - dltTransactionIdHex + error { + message + name + } + succeed + } + } +` + +const registerAddress = gql` + mutation ($input: UserAccountDraft!) { + registerAddress(data: $input) { + error { + message + name + } + succeed } } ` @@ -63,7 +82,10 @@ export class DltConnectorClient { if (!DltConnectorClient.instance.client) { try { DltConnectorClient.instance.client = new GraphQLClient(CONFIG.DLT_CONNECTOR_URL, { - method: 'GET', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, jsonSerializer: { parse: JSON.parse, stringify: JSON.stringify, @@ -118,7 +140,45 @@ export class DltConnectorClient { } return succeed } catch (e) { + console.log("catch response dlt:", e) throw new LogError('Error send sending transaction to dlt-connector: ', e) } } + + public async registerAddress(dbUser: User): Promise { + console.log('dlt:registerAddress') + const params = { + input: { + user: { + uuid: dbUser.gradidoID, + communityUuid: dbUser.communityUuid, + accountNr: 1, + } as UserIdentifier, + createdAt: dbUser.createdAt.toISOString(), + accountType: AccountType.COMMUNITY_HUMAN, + } as UserAccountDraft, + } + try { + console.log('before send with', params) + const { + data: { registerAddress: result }, + } = await this.client.rawRequest<{ registerAddress: TransactionResult }>( + registerAddress, + params, + ) + console.log('after send') + console.log('result: ', result) + logger.info('send register address transaction to dlt-connector', { + params, + result, + }) + if (result.error) { + logger.error('Error sending register address transaction to dlt-connector', result.error) + } + return result + } catch (e) { + console.log('exception', e) + logger.error('Exception sending register address transaction to dlt-connector', e) + } + } } diff --git a/backend/src/apis/dltConnector/enum/AccountType.ts b/backend/src/apis/dltConnector/enum/AccountType.ts new file mode 100644 index 000000000..a54703fbd --- /dev/null +++ b/backend/src/apis/dltConnector/enum/AccountType.ts @@ -0,0 +1,9 @@ +export enum AccountType { + NONE = 'NONE', // if no address was found + COMMUNITY_HUMAN = 'COMMUNITY_HUMAN', // creation account for human + COMMUNITY_GMW = 'COMMUNITY_GMW', // community public budget account + COMMUNITY_AUF = 'COMMUNITY_AUF', // community compensation and environment founds account + COMMUNITY_PROJECT = 'COMMUNITY_PROJECT', // no creations allowed + SUBACCOUNT = 'SUBACCOUNT', // no creations allowed + CRYPTO_ACCOUNT = 'CRYPTO_ACCOUNT', // user control his keys, no creations +} diff --git a/backend/src/apis/dltConnector/model/UserAccountDraft.ts b/backend/src/apis/dltConnector/model/UserAccountDraft.ts new file mode 100644 index 000000000..f4aff4cb4 --- /dev/null +++ b/backend/src/apis/dltConnector/model/UserAccountDraft.ts @@ -0,0 +1,9 @@ +import { AccountType } from '@/apis/dltConnector/enum/AccountType' + +import { UserIdentifier } from './UserIdentifier' + +export interface UserAccountDraft { + user: UserIdentifier + createdAt: string + accountType: AccountType +} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 3f70ce112..8c7d56985 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -30,6 +30,7 @@ import { SearchAdminUsersResult } from '@model/AdminUser' import { User } from '@model/User' import { UserAdmin, SearchUsersResult } from '@model/UserAdmin' +import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' import { subscribe } from '@/apis/KlicktippController' import { encode } from '@/auth/JWT' import { RIGHTS } from '@/auth/RIGHTS' @@ -359,6 +360,12 @@ export class UserResolver { } logger.info('createUser() successful...') + const dltConnector = DltConnectorClient.getInstance() + if (dltConnector) { + const r = await dltConnector.registerAddress(dbUser) + console.log('result from dlt', r) + } + if (redeemCode) { eventRegisterRedeem.affectedUser = dbUser eventRegisterRedeem.actingUser = dbUser From 9ce8dfd493b3780fd80f1b1ae41bf5337a030710 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 14 May 2024 11:56:07 +0200 Subject: [PATCH 003/226] refactor dlt-connector a bit, fix some wrong code --- dlt-connector/src/config/index.ts | 2 +- dlt-connector/src/data/Community.repository.ts | 6 ++++++ dlt-connector/src/graphql/resolver/AccountsResolver.ts | 8 ++++++-- dlt-connector/src/graphql/schema.ts | 3 ++- .../backendToDb/account/RegisterAddress.context.ts | 4 +++- .../transaction/CreateTransactionRecipe.context.ts | 4 ++++ .../transaction/RegisterAddressTransaction.role.ts | 3 +++ 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 6b4fdae9a..9cbdac441 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -4,7 +4,7 @@ dotenv.config() const constants = { LOG4JS_CONFIG: 'log4js-config.json', - DB_VERSION: '0003-refactor_transaction_recipe', + DB_VERSION: '0004-fix_spelling', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { diff --git a/dlt-connector/src/data/Community.repository.ts b/dlt-connector/src/data/Community.repository.ts index 78023b15e..dca283a67 100644 --- a/dlt-connector/src/data/Community.repository.ts +++ b/dlt-connector/src/data/Community.repository.ts @@ -73,4 +73,10 @@ export const CommunityRepository = getDataSource() } return new KeyPair(community) }, + + async loadHomeCommunity(): Promise { + return await this.findOneOrFail({ + where: { foreign: false }, + }) + }, }) diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts index 91ac7bd73..b90b5561c 100644 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -1,11 +1,11 @@ +import { TransactionRecipe } from '@model/TransactionRecipe' import { Arg, Mutation, Query, Resolver } from 'type-graphql' import { QueryFailedError } from 'typeorm' -import { TransactionRecipe } from '@model/TransactionRecipe' - import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' import { UserRepository } from '@/data/User.repository' import { RegisterAddressContext } from '@/interactions/backendToDb/account/RegisterAddress.context' +import { AccountLoggingView } from '@/logging/AccountLogging.view' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' @@ -33,6 +33,10 @@ export class AccountResolver { const registerAddressContext = new RegisterAddressContext(userAccountDraft) try { const { transaction, account } = await registerAddressContext.run() + logger.info('register address', { + account: new AccountLoggingView(account), + transaction: new TransactionLoggingView(transaction), + }) await getDataSource().transaction(async (transactionalEntityManager) => { await transactionalEntityManager.save(account) await transactionalEntityManager.save(transaction) diff --git a/dlt-connector/src/graphql/schema.ts b/dlt-connector/src/graphql/schema.ts index bbd61c63f..a756b1ac9 100755 --- a/dlt-connector/src/graphql/schema.ts +++ b/dlt-connector/src/graphql/schema.ts @@ -2,13 +2,14 @@ import { Decimal } from 'decimal.js-light' import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' +import { AccountResolver } from './resolver/AccountsResolver' import { CommunityResolver } from './resolver/CommunityResolver' import { TransactionResolver } from './resolver/TransactionsResolver' import { DecimalScalar } from './scalar/Decimal' export const schema = async (): Promise => { return buildSchema({ - resolvers: [TransactionResolver, CommunityResolver], + resolvers: [TransactionResolver, CommunityResolver, AccountResolver], scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], validate: { validationError: { target: false }, diff --git a/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts b/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts index 196c0daf4..c84cb0149 100644 --- a/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts +++ b/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts @@ -25,7 +25,8 @@ export class RegisterAddressContext { public constructor(private userAccountDraft: UserAccountDraft) {} public async run(): Promise { - const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() + const community = await CommunityRepository.loadHomeCommunity() + const communityKeyPair = new KeyPair(community) const user = await this.loadOrCreateUser(communityKeyPair) if (this.isAccountAlreadyExistOnUser(user)) { throw new TransactionError( @@ -37,6 +38,7 @@ export class RegisterAddressContext { const account = this.createAccount(new UserLogic(user).calculateKeyPair(communityKeyPair)) account.user = user const createTransactionContext = new CreateTransactionRecipeContext(this.userAccountDraft, { + community, account, }) await createTransactionContext.run() diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts index 42e633a18..abd87616b 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts @@ -74,9 +74,13 @@ export class CreateTransactionRecipeContext { if (!this.data?.account) { throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'account was not set') } + if (!this.data.community) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community was not set') + } this.transactionRecipe = await new RegisterAddressTransactionRole().create( this.draft, this.data.account, + this.data.community, ) return true } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts index 84de6b5df..8b342b1fd 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts @@ -1,4 +1,5 @@ import { Account } from '@entity/Account' +import { Community } from '@entity/Community' import { AccountLogic } from '@/data/Account.logic' import { CommunityRepository } from '@/data/Community.repository' @@ -13,6 +14,7 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRecipeRol async create( userAccountDraft: UserAccountDraft, account: Account, + community: Community, ): Promise { const bodyBuilder = new TransactionBodyBuilder() const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() @@ -22,6 +24,7 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRecipeRol } this.transactionBuilder .fromTransactionBodyBuilder(bodyBuilder.fromUserAccountDraft(userAccountDraft, account)) + .setCommunity(community) .setSignature(signingKeyPair.sign(this.transactionBuilder.getTransaction().bodyBytes)) .setSigningAccount(account) return this From 64008b1564316ba5806393375460f9adb4535824 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 14 May 2024 12:48:25 +0200 Subject: [PATCH 004/226] fix test and lint --- .../apis/dltConnector/DltConnectorClient.ts | 6 --- .../src/graphql/resolver/AccountsResolver.ts | 3 +- .../CreateTransactionRecipe.context.test.ts | 44 ++++++++++++++++++- .../CreateTransactionRecipe.context.ts | 6 ++- dlt-connector/test/seeding/Community.seed.ts | 2 +- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 4cdbffddf..c8d5e4276 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -140,13 +140,11 @@ export class DltConnectorClient { } return succeed } catch (e) { - console.log("catch response dlt:", e) throw new LogError('Error send sending transaction to dlt-connector: ', e) } } public async registerAddress(dbUser: User): Promise { - console.log('dlt:registerAddress') const params = { input: { user: { @@ -159,15 +157,12 @@ export class DltConnectorClient { } as UserAccountDraft, } try { - console.log('before send with', params) const { data: { registerAddress: result }, } = await this.client.rawRequest<{ registerAddress: TransactionResult }>( registerAddress, params, ) - console.log('after send') - console.log('result: ', result) logger.info('send register address transaction to dlt-connector', { params, result, @@ -177,7 +172,6 @@ export class DltConnectorClient { } return result } catch (e) { - console.log('exception', e) logger.error('Exception sending register address transaction to dlt-connector', e) } } diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts index b90b5561c..7f782af89 100644 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -1,7 +1,8 @@ -import { TransactionRecipe } from '@model/TransactionRecipe' import { Arg, Mutation, Query, Resolver } from 'type-graphql' import { QueryFailedError } from 'typeorm' +import { TransactionRecipe } from '@model/TransactionRecipe' + import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' import { UserRepository } from '@/data/User.repository' import { RegisterAddressContext } from '@/interactions/backendToDb/account/RegisterAddress.context' diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts index 117645bd1..3d3998db1 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts @@ -1,5 +1,6 @@ import 'reflect-metadata' import { Account } from '@entity/Account' +import { Community } from '@entity/Community' import { Decimal } from 'decimal.js-light' import { v4 } from 'uuid' @@ -8,11 +9,14 @@ import { TestDB } from '@test/TestDB' import { CONFIG } from '@/config' import { KeyPair } from '@/data/KeyPair' import { Mnemonic } from '@/data/Mnemonic' +import { AddressType } from '@/data/proto/3_3/enum/AddressType' import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' import { TransactionBody } from '@/data/proto/3_3/TransactionBody' +import { AccountType } from '@/graphql/enum/AccountType' import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' import { CreateTransactionRecipeContext } from './CreateTransactionRecipe.context' @@ -39,6 +43,7 @@ let moderator: UserSet let firstUser: UserSet let secondUser: UserSet let foreignUser: UserSet +let homeCommunity: Community const topic = iotaTopicFromCommunityUUID(homeCommunityUuid) const foreignTopic = iotaTopicFromCommunityUUID(foreignCommunityUuid) @@ -46,7 +51,7 @@ const foreignTopic = iotaTopicFromCommunityUUID(foreignCommunityUuid) describe('interactions/backendToDb/transaction/Create Transaction Recipe Context Test', () => { beforeAll(async () => { await TestDB.instance.setupTestDB() - await communitySeed(homeCommunityUuid, false) + homeCommunity = await communitySeed(homeCommunityUuid, false) await communitySeed(foreignCommunityUuid, true, foreignKeyPair) moderator = createUserSet(homeCommunityUuid, keyPair) @@ -66,6 +71,43 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context await TestDB.instance.teardownTestDB() }) + it('register address transaction', async () => { + const userAccountDraft = new UserAccountDraft() + userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN + userAccountDraft.createdAt = new Date().toISOString() + userAccountDraft.user = firstUser.identifier + const context = new CreateTransactionRecipeContext(userAccountDraft, { + account: firstUser.account, + community: homeCommunity, + }) + await context.run() + const transaction = context.getTransactionRecipe() + expect(transaction).toMatchObject({ + type: TransactionType.REGISTER_ADDRESS, + protocolVersion: '3.3', + community: { + rootPubkey: keyPair.publicKey, + foreign: 0, + iotaTopic: topic, + }, + signingAccount: { + derive2Pubkey: firstUser.account.derive2Pubkey, + }, + }) + + const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) + expect(body.registerAddress).toBeDefined() + if (!body.registerAddress) throw new Error() + + expect(body).toMatchObject({ + type: CrossGroupType.LOCAL, + registerAddress: { + derivationIndex: 1, + addressType: AddressType.COMMUNITY_HUMAN, + }, + }) + }) + it('creation transaction', async () => { const creationTransactionDraft = new TransactionDraft() creationTransactionDraft.amount = new Decimal('2000') diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts index abd87616b..eb6d6dffd 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts @@ -45,7 +45,6 @@ export class CreateTransactionRecipeContext { */ public async run(): Promise { if (this.draft instanceof TransactionDraft) { - const transactionRecipeRole = new BalanceChangingTransactionRecipeRole() // contain logic for translation from backend to dlt-connector format let transactionTypeRole: AbstractTransactionRole switch (this.draft.type) { @@ -59,7 +58,10 @@ export class CreateTransactionRecipeContext { transactionTypeRole = new ReceiveTransactionRole(this.draft) break } - await transactionRecipeRole.create(this.draft, transactionTypeRole) + this.transactionRecipe = await new BalanceChangingTransactionRecipeRole().create( + this.draft, + transactionTypeRole, + ) return true } else if (this.draft instanceof CommunityDraft) { if (!this.data?.community) { diff --git a/dlt-connector/test/seeding/Community.seed.ts b/dlt-connector/test/seeding/Community.seed.ts index a1b042ef2..9c492eedb 100644 --- a/dlt-connector/test/seeding/Community.seed.ts +++ b/dlt-connector/test/seeding/Community.seed.ts @@ -20,7 +20,7 @@ export const communitySeed = async ( const community = await Community.findOneOrFail({ where: { iotaTopic } }) if (foreign && keyPair) { - // that isn't entirely correct, normally only the public key from foreign community is know, and will be come form blockchain + // that isn't entirely correct, normally only the public key from foreign community is known, and will be come form blockchain keyPair.fillInCommunityKeys(community) await community.save() } From 0bb04a845ae66abe369cc8f4ba1b5bdd217b6299 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 20 Sep 2024 17:22:41 +0200 Subject: [PATCH 005/226] refactor with gradido-blockchain-js --- .../apis/dltConnector/DltConnectorClient.ts | 4 + dlt-connector/.env.dist | 5 + dlt-connector/.env.template | 5 + dlt-connector/package.json | 6 +- dlt-connector/src/config/index.ts | 14 +- dlt-connector/src/data/Account.factory.ts | 11 +- dlt-connector/src/data/Account.test.ts | 26 +- .../src/data/BackendTransaction.factory.ts | 13 - .../src/data/BackendTransaction.repository.ts | 7 - .../src/data/Community.repository.ts | 4 +- dlt-connector/src/data/KeyPair.ts | 119 +- dlt-connector/src/data/Mnemonic.ts | 48 - dlt-connector/src/data/Transaction.builder.ts | 102 +- .../src/data/Transaction.logic.test.ts | 323 -- dlt-connector/src/data/Transaction.logic.ts | 200 -- .../src/data/proto/3_3/CommunityRoot.ts | 35 - .../data/proto/3_3/ConfirmedTransaction.ts | 41 - .../data/proto/3_3/GradidoCreation.test.ts | 22 - .../src/data/proto/3_3/GradidoCreation.ts | 53 - .../data/proto/3_3/GradidoDeferredTransfer.ts | 42 - .../src/data/proto/3_3/GradidoTransaction.ts | 48 - .../src/data/proto/3_3/GradidoTransfer.ts | 49 - .../src/data/proto/3_3/GroupFriendsUpdate.ts | 23 - .../src/data/proto/3_3/RegisterAddress.ts | 49 - .../src/data/proto/3_3/SignatureMap.ts | 14 - .../src/data/proto/3_3/SignaturePair.ts | 15 - .../src/data/proto/3_3/Timestamp.test.ts | 16 - dlt-connector/src/data/proto/3_3/Timestamp.ts | 27 - .../data/proto/3_3/TimestampSeconds.test.ts | 14 - .../src/data/proto/3_3/TimestampSeconds.ts | 20 - .../src/data/proto/3_3/TransactionBody.ts | 157 - .../src/data/proto/3_3/TransferAmount.ts | 16 - dlt-connector/src/data/proto/3_3/const.ts | 1 - .../src/data/proto/3_3/enum/AddressType.ts | 14 - .../src/data/proto/3_3/enum/CrossGroupType.ts | 22 - .../data/proto/3_3/enum/TransactionType.ts | 4 +- .../src/data/proto/AbstractTransaction.ts | 5 - .../src/data/proto/TransactionBody.builder.ts | 147 - .../src/data/proto/transactionBody.logic.ts | 59 - .../src/graphql/enum/TransactionErrorType.ts | 1 + .../src/graphql/model/TransactionRecipe.ts | 6 +- .../src/graphql/resolver/CommunityResolver.ts | 3 +- .../graphql/resolver/TransactionsResolver.ts | 33 +- dlt-connector/src/index.ts | 19 +- .../community/HomeCommunity.role.ts | 1 + .../transaction/AbstractTransaction.role.ts | 55 +- .../BalanceChangingTransactionRecipeRole.ts | 74 +- .../CommunityRootTransaction.role.ts | 27 +- .../CreateTransactionRecipe.context.test.ts | 146 +- .../CreateTransactionRecipe.context.ts | 4 +- .../transaction/CreationTransaction.role.ts | 25 +- .../transaction/ReceiveTransaction.role.ts | 21 - .../RegisterAddressTransaction.role.ts | 30 +- .../transaction/SendTransaction.role.ts | 26 +- .../AbstractTransactionRecipe.role.ts | 78 +- .../InboundTransactionRecipe.role.ts | 12 +- .../LocalTransactionRecipe.role.ts | 13 +- .../OutboundTransactionRecipeRole.ts | 6 +- .../TransmitToIota.context.test.ts | 18 +- .../transmitToIota/TransmitToIota.context.ts | 32 +- .../src/logging/AbstractLogging.view.ts | 13 +- .../src/logging/AccountLogging.view.ts | 9 +- .../src/logging/CommunityRootLogging.view.ts | 18 - .../ConfirmedTransactionLogging.view.ts | 24 - .../logging/GradidoCreationLogging.view.ts | 18 - .../GradidoDeferredTransferLogging.view.ts | 18 - .../logging/GradidoTransactionLogging.view.ts | 29 - .../logging/GradidoTransferLogging.view.ts | 18 - .../logging/GroupFriendsUpdateLogging.view.ts | 16 - .../logging/RegisterAddressLogging.view.ts | 22 - .../src/logging/SignatureMapLogging.view.ts | 17 - .../src/logging/SignaturePairLogging.view.ts | 18 - .../logging/TransactionBodyLogging.view.ts | 46 - .../src/logging/TransferAmountLogging.view.ts | 18 - .../src/utils/derivationHelper.test.ts | 6 - dlt-connector/src/utils/typeConverter.test.ts | 24 +- dlt-connector/src/utils/typeConverter.ts | 101 +- dlt-connector/yarn.lock | 2783 +++++++++-------- .../BackendTransaction.ts | 3 +- .../Transaction.ts | 3 +- .../entity/0004-fix_spelling/Transaction.ts | 3 +- .../Community.ts | 64 + .../Transaction.ts | 109 + dlt-database/entity/BackendTransaction.ts | 1 - dlt-database/entity/Community.ts | 2 +- dlt-database/entity/Transaction.ts | 2 +- dlt-database/entity/index.ts | 2 - ...05-refactor_with_gradido_blockchain_lib.ts | 28 + dlt-database/yarn.lock | 2017 ++++++------ 89 files changed, 3340 insertions(+), 4502 deletions(-) delete mode 100644 dlt-connector/src/data/BackendTransaction.factory.ts delete mode 100644 dlt-connector/src/data/BackendTransaction.repository.ts delete mode 100644 dlt-connector/src/data/Mnemonic.ts delete mode 100644 dlt-connector/src/data/Transaction.logic.test.ts delete mode 100644 dlt-connector/src/data/Transaction.logic.ts delete mode 100644 dlt-connector/src/data/proto/3_3/CommunityRoot.ts delete mode 100644 dlt-connector/src/data/proto/3_3/ConfirmedTransaction.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GradidoCreation.test.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GradidoCreation.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GradidoDeferredTransfer.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GradidoTransaction.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GradidoTransfer.ts delete mode 100644 dlt-connector/src/data/proto/3_3/GroupFriendsUpdate.ts delete mode 100644 dlt-connector/src/data/proto/3_3/RegisterAddress.ts delete mode 100644 dlt-connector/src/data/proto/3_3/SignatureMap.ts delete mode 100644 dlt-connector/src/data/proto/3_3/SignaturePair.ts delete mode 100644 dlt-connector/src/data/proto/3_3/Timestamp.test.ts delete mode 100644 dlt-connector/src/data/proto/3_3/Timestamp.ts delete mode 100644 dlt-connector/src/data/proto/3_3/TimestampSeconds.test.ts delete mode 100644 dlt-connector/src/data/proto/3_3/TimestampSeconds.ts delete mode 100644 dlt-connector/src/data/proto/3_3/TransactionBody.ts delete mode 100644 dlt-connector/src/data/proto/3_3/TransferAmount.ts delete mode 100644 dlt-connector/src/data/proto/3_3/const.ts delete mode 100644 dlt-connector/src/data/proto/3_3/enum/AddressType.ts delete mode 100644 dlt-connector/src/data/proto/3_3/enum/CrossGroupType.ts delete mode 100644 dlt-connector/src/data/proto/AbstractTransaction.ts delete mode 100644 dlt-connector/src/data/proto/TransactionBody.builder.ts delete mode 100644 dlt-connector/src/data/proto/transactionBody.logic.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/ReceiveTransaction.role.ts delete mode 100644 dlt-connector/src/logging/CommunityRootLogging.view.ts delete mode 100644 dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts delete mode 100644 dlt-connector/src/logging/GradidoCreationLogging.view.ts delete mode 100644 dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts delete mode 100644 dlt-connector/src/logging/GradidoTransactionLogging.view.ts delete mode 100644 dlt-connector/src/logging/GradidoTransferLogging.view.ts delete mode 100644 dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts delete mode 100644 dlt-connector/src/logging/RegisterAddressLogging.view.ts delete mode 100644 dlt-connector/src/logging/SignatureMapLogging.view.ts delete mode 100644 dlt-connector/src/logging/SignaturePairLogging.view.ts delete mode 100644 dlt-connector/src/logging/TransactionBodyLogging.view.ts delete mode 100644 dlt-connector/src/logging/TransferAmountLogging.view.ts create mode 100644 dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts create mode 100644 dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts delete mode 100644 dlt-database/entity/BackendTransaction.ts create mode 100644 dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index c8d5e4276..85e8bfb0a 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -104,6 +104,10 @@ export class DltConnectorClient { * and update dltTransactionId of transaction in db with iota message id */ public async transmitTransaction(transaction: DbTransaction): Promise { + // we don't need the receive transactions, there contain basically the same data as the send transactions + if ((transaction.typeId as TransactionTypeId) === TransactionTypeId.RECEIVE) { + return true + } const typeString = getTransactionTypeString(transaction.typeId) // no negative values in dlt connector, gradido concept don't use negative values so the code don't use it too const amountString = transaction.amount.abs().toString() diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 50e9fe8e1..164e23036 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -21,6 +21,11 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log # DLT-Connector DLT_CONNECTOR_PORT=6010 +# Gradido Blockchain +GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=21ffbbc616fe +GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=a51ef8ac7ef1abf162fb7a65261acd7a +GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD=YourPassword + # Route to Backend BACKEND_SERVER_URL=http://localhost:4000 JWT_SECRET=secret123 \ No newline at end of file diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 2e123ca81..d7d46dad7 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -19,5 +19,10 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log # DLT-Connector DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT +# Gradido Blockchain +GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET +GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY +GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD=$GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD + # Route to Backend BACKEND_SERVER_URL=http://localhost:4000 \ No newline at end of file diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 30cd4b33b..b9de6338b 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -19,17 +19,15 @@ "@apollo/server": "^4.7.5", "@apollo/utils.fetcher": "^3.0.0", "@iota/client": "^2.2.4", - "bip32-ed25519": "^0.0.4", - "bip39": "^3.1.0", "body-parser": "^1.20.2", "class-validator": "^0.14.0", "cors": "^2.8.5", "cross-env": "^7.0.3", - "decimal.js-light": "^2.5.1", "dlt-database": "file:../dlt-database", "dotenv": "10.0.0", "express": "4.17.1", "express-slow-down": "^2.0.1", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#master", "graphql": "^16.7.1", "graphql-request": "^6.1.0", "graphql-scalars": "^1.22.2", @@ -37,9 +35,7 @@ "jose": "^5.2.2", "log4js": "^6.7.1", "nodemon": "^2.0.20", - "protobufjs": "^7.2.5", "reflect-metadata": "^0.1.13", - "sodium-native": "^4.0.4", "tsconfig-paths": "^4.1.2", "type-graphql": "^2.0.0-beta.2", "uuid": "^9.0.1" diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 9cbdac441..f2f01cd8d 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -4,12 +4,12 @@ dotenv.config() const constants = { LOG4JS_CONFIG: 'log4js-config.json', - DB_VERSION: '0004-fix_spelling', + DB_VERSION: '0005-refactor_with_gradido_blockchain_lib', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v6.2024-02-20', + EXPECTED: 'v7.2024-09-24', CURRENT: '', }, } @@ -39,6 +39,15 @@ const dltConnector = { DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT ?? 6010, } +const gradidoBlockchain = { + GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: + process.env.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET ?? 'invalid', + GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: + process.env.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY ?? 'invalid', + GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD: + process.env.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD, +} + const backendServer = { BACKEND_SERVER_URL: process.env.BACKEND_SERVER_URL ?? 'http://backend:4000', } @@ -61,5 +70,6 @@ export const CONFIG = { ...database, ...iota, ...dltConnector, + ...gradidoBlockchain, ...backendServer, } diff --git a/dlt-connector/src/data/Account.factory.ts b/dlt-connector/src/data/Account.factory.ts index a8c1f162d..fc20a0acc 100644 --- a/dlt-connector/src/data/Account.factory.ts +++ b/dlt-connector/src/data/Account.factory.ts @@ -1,8 +1,13 @@ +/* eslint-disable camelcase */ import { Account } from '@entity/Account' import Decimal from 'decimal.js-light' +import { + AddressType, + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, +} from 'gradido-blockchain-js' import { KeyPair } from '@/data/KeyPair' -import { AddressType } from '@/data/proto/3_3/enum/AddressType' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { hardenDerivationIndex } from '@/utils/derivationHelper' import { accountTypeToAddressType } from '@/utils/typeConverter' @@ -44,7 +49,7 @@ export class AccountFactory { return AccountFactory.createAccount( createdAt, hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), - AddressType.COMMUNITY_GMW, + AddressType_COMMUNITY_GMW, keyPair, ) } @@ -53,7 +58,7 @@ export class AccountFactory { return AccountFactory.createAccount( createdAt, hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), - AddressType.COMMUNITY_AUF, + AddressType_COMMUNITY_AUF, keyPair, ) } diff --git a/dlt-connector/src/data/Account.test.ts b/dlt-connector/src/data/Account.test.ts index f28065cce..130908de6 100644 --- a/dlt-connector/src/data/Account.test.ts +++ b/dlt-connector/src/data/Account.test.ts @@ -1,8 +1,15 @@ +/* eslint-disable camelcase */ import 'reflect-metadata' import { Decimal } from 'decimal.js-light' import { TestDB } from '@test/TestDB' +import { + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, + AddressType_COMMUNITY_HUMAN, +} from 'gradido-blockchain-js' + import { AccountType } from '@/graphql/enum/AccountType' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { UserIdentifier } from '@/graphql/input/UserIdentifier' @@ -11,7 +18,6 @@ import { AccountFactory } from './Account.factory' import { AccountRepository } from './Account.repository' import { KeyPair } from './KeyPair' import { Mnemonic } from './Mnemonic' -import { AddressType } from './proto/3_3/enum/AddressType' import { UserFactory } from './User.factory' import { UserLogic } from './User.logic' @@ -37,14 +43,14 @@ describe('data/Account test factory and repository', () => { }) it('test createAccount', () => { - const account = AccountFactory.createAccount(now, 1, AddressType.COMMUNITY_HUMAN, keyPair1) + const account = AccountFactory.createAccount(now, 1, AddressType_COMMUNITY_HUMAN, keyPair1) expect(account).toMatchObject({ derivationIndex: 1, derive2Pubkey: Buffer.from( 'cb88043ef4833afc01d6ed9b34e1aa48e79dce5ff97c07090c6600ec05f6d994', 'hex', ), - type: AddressType.COMMUNITY_HUMAN, + type: AddressType_COMMUNITY_HUMAN, createdAt: now, balanceCreatedAt: now, balanceOnConfirmation: new Decimal(0), @@ -65,7 +71,7 @@ describe('data/Account test factory and repository', () => { 'cb88043ef4833afc01d6ed9b34e1aa48e79dce5ff97c07090c6600ec05f6d994', 'hex', ), - type: AddressType.COMMUNITY_HUMAN, + type: AddressType_COMMUNITY_HUMAN, createdAt: now, balanceCreatedAt: now, balanceOnConfirmation: new Decimal(0), @@ -81,7 +87,7 @@ describe('data/Account test factory and repository', () => { '05f0060357bb73bd290283870fc47a10b3764f02ca26938479ed853f46145366', 'hex', ), - type: AddressType.COMMUNITY_GMW, + type: AddressType_COMMUNITY_GMW, createdAt: now, balanceCreatedAt: now, balanceOnConfirmation: new Decimal(0), @@ -97,7 +103,7 @@ describe('data/Account test factory and repository', () => { '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex', ), - type: AddressType.COMMUNITY_AUF, + type: AddressType_COMMUNITY_AUF, createdAt: now, balanceCreatedAt: now, balanceOnConfirmation: new Decimal(0), @@ -151,7 +157,7 @@ describe('data/Account test factory and repository', () => { '0fa996b73b624592fe326b8500cb1e3f10026112b374d84c87d097f4d489c019', 'hex', ), - type: AddressType.COMMUNITY_GMW, + type: AddressType_COMMUNITY_GMW, }), expect.objectContaining({ derivationIndex: 2147483650, @@ -159,7 +165,7 @@ describe('data/Account test factory and repository', () => { '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex', ), - type: AddressType.COMMUNITY_AUF, + type: AddressType_COMMUNITY_AUF, }), ]), ) @@ -176,7 +182,7 @@ describe('data/Account test factory and repository', () => { '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex', ), - type: AddressType.COMMUNITY_AUF, + type: AddressType_COMMUNITY_AUF, }) }) @@ -190,7 +196,7 @@ describe('data/Account test factory and repository', () => { '2099c004a26e5387c9fbbc9bb0f552a9642d3fd7c710ae5802b775d24ff36f93', 'hex', ), - type: AddressType.COMMUNITY_HUMAN, + type: AddressType_COMMUNITY_HUMAN, }) }) }) diff --git a/dlt-connector/src/data/BackendTransaction.factory.ts b/dlt-connector/src/data/BackendTransaction.factory.ts deleted file mode 100644 index 365da0693..000000000 --- a/dlt-connector/src/data/BackendTransaction.factory.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BackendTransaction } from '@entity/BackendTransaction' - -import { TransactionDraft } from '@/graphql/input/TransactionDraft' - -export class BackendTransactionFactory { - public static createFromTransactionDraft(transactionDraft: TransactionDraft): BackendTransaction { - const backendTransaction = BackendTransaction.create() - backendTransaction.backendTransactionId = transactionDraft.backendTransactionId - backendTransaction.typeId = transactionDraft.type - backendTransaction.createdAt = new Date(transactionDraft.createdAt) - return backendTransaction - } -} diff --git a/dlt-connector/src/data/BackendTransaction.repository.ts b/dlt-connector/src/data/BackendTransaction.repository.ts deleted file mode 100644 index b4e566659..000000000 --- a/dlt-connector/src/data/BackendTransaction.repository.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { BackendTransaction } from '@entity/BackendTransaction' - -import { getDataSource } from '@/typeorm/DataSource' - -export const BackendTransactionRepository = getDataSource() - .getRepository(BackendTransaction) - .extend({}) diff --git a/dlt-connector/src/data/Community.repository.ts b/dlt-connector/src/data/Community.repository.ts index dca283a67..a9fdf4e09 100644 --- a/dlt-connector/src/data/Community.repository.ts +++ b/dlt-connector/src/data/Community.repository.ts @@ -66,9 +66,9 @@ export const CommunityRepository = getDataSource() async loadHomeCommunityKeyPair(): Promise { const community = await this.findOneOrFail({ where: { foreign: false }, - select: { rootChaincode: true, rootPubkey: true, rootPrivkey: true }, + select: { rootChaincode: true, rootPubkey: true, rootEncryptedPrivkey: true }, }) - if (!community.rootChaincode || !community.rootPrivkey) { + if (!community.rootChaincode || !community.rootEncryptedPrivkey) { throw new LogError('Missing chaincode or private key for home community') } return new KeyPair(community) diff --git a/dlt-connector/src/data/KeyPair.ts b/dlt-connector/src/data/KeyPair.ts index dc2dd1bab..61207ee7e 100644 --- a/dlt-connector/src/data/KeyPair.ts +++ b/dlt-connector/src/data/KeyPair.ts @@ -1,40 +1,52 @@ import { Community } from '@entity/Community' - // https://www.npmjs.com/package/bip32-ed25519 +import { + KeyPairEd25519, + MemoryBlock, + Passphrase, + SecretKeyCryptography, + SignaturePair, +} from 'gradido-blockchain-js' + +import { CONFIG } from '@/config' import { LogError } from '@/server/LogError' -import { toPublic, derivePrivate, sign, verify, generateFromSeed } from 'bip32-ed25519' - -import { Mnemonic } from './Mnemonic' -import { SignaturePair } from './proto/3_3/SignaturePair' - /** * Class Managing Key Pair and also generate, sign and verify signature with it */ export class KeyPair { - private _publicKey: Buffer - private _chainCode: Buffer - private _privateKey: Buffer - + private _ed25519KeyPair: KeyPairEd25519 /** - * @param input: Mnemonic = Mnemonic or Passphrase which work as seed for generating algorithms - * @param input: Buffer = extended private key, returned from bip32-ed25519 generateFromSeed or from derivePrivate + * @param input: KeyPairEd25519 = already loaded KeyPairEd25519 + * @param input: Passphrase = Passphrase which work as seed for generating algorithms + * @param input: MemoryBlock = a seed at least 32 byte * @param input: Community = community entity with keys loaded from db - * */ - public constructor(input: Mnemonic | Buffer | Community) { - if (input instanceof Mnemonic) { - this.loadFromExtendedPrivateKey(generateFromSeed(input.seed)) - } else if (input instanceof Buffer) { - this.loadFromExtendedPrivateKey(input) + public constructor(input: KeyPairEd25519 | Passphrase | MemoryBlock | Community) { + let keyPair: KeyPairEd25519 | null = null + if (input instanceof KeyPairEd25519) { + keyPair = input + } else if (input instanceof Passphrase) { + keyPair = KeyPairEd25519.create(input) + } else if (input instanceof MemoryBlock) { + keyPair = KeyPairEd25519.create(input) } else if (input instanceof Community) { - if (!input.rootPrivkey || !input.rootChaincode || !input.rootPubkey) { - throw new LogError('missing private key or chaincode or public key in commmunity entity') + if (!input.rootEncryptedPrivkey || !input.rootChaincode || !input.rootPubkey) { + throw new LogError( + 'missing encrypted private key or chaincode or public key in commmunity entity', + ) } - this._privateKey = input.rootPrivkey - this._publicKey = input.rootPubkey - this._chainCode = input.rootChaincode + const secretBox = this.createSecretBox(input.iotaTopic) + keyPair = new KeyPairEd25519( + new MemoryBlock(input.rootPubkey), + secretBox.decrypt(new MemoryBlock(input.rootEncryptedPrivkey)), + new MemoryBlock(input.rootChaincode), + ) } + if (!keyPair) { + throw new LogError("couldn't create KeyPairEd25519 from input") + } + this._ed25519KeyPair = keyPair } /** @@ -42,47 +54,54 @@ export class KeyPair { * @param community */ public fillInCommunityKeys(community: Community) { - community.rootPubkey = this._publicKey - community.rootPrivkey = this._privateKey - community.rootChaincode = this._chainCode - } - - private loadFromExtendedPrivateKey(extendedPrivateKey: Buffer) { - if (extendedPrivateKey.length !== 96) { - throw new LogError('invalid extended private key') - } - this._privateKey = extendedPrivateKey.subarray(0, 64) - this._chainCode = extendedPrivateKey.subarray(64, 96) - this._publicKey = toPublic(extendedPrivateKey).subarray(0, 32) - } - - public getExtendPrivateKey(): Buffer { - return Buffer.concat([this._privateKey, this._chainCode]) - } - - public getExtendPublicKey(): Buffer { - return Buffer.concat([this._publicKey, this._chainCode]) + const secretBox = this.createSecretBox(community.iotaTopic) + community.rootPubkey = this._ed25519KeyPair.getPublicKey()?.data() + community.rootEncryptedPrivkey = this._ed25519KeyPair.getCryptedPrivKey(secretBox).data() + community.rootChaincode = this._ed25519KeyPair.getChainCode()?.data() } public get publicKey(): Buffer { - return this._publicKey + const publicKey = this._ed25519KeyPair.getPublicKey() + if (!publicKey) { + throw new LogError('invalid key pair, get empty public key') + } + return publicKey.data() + } + + public get keyPair(): KeyPairEd25519 { + return this._ed25519KeyPair } public derive(path: number[]): KeyPair { - const extendedPrivateKey = this.getExtendPrivateKey() return new KeyPair( path.reduce( - (extendPrivateKey: Buffer, node: number) => derivePrivate(extendPrivateKey, node), - extendedPrivateKey, + (keyPair: KeyPairEd25519, node: number) => keyPair.deriveChild(node), + this._ed25519KeyPair, ), ) } public sign(message: Buffer): Buffer { - return sign(message, this.getExtendPrivateKey()) + return this._ed25519KeyPair.sign(new MemoryBlock(message)).data() } - public static verify(message: Buffer, { signature, pubKey }: SignaturePair): boolean { - return verify(message, signature, pubKey) + public static verify(message: Buffer, signaturePair: SignaturePair): boolean { + const publicKeyPair = new KeyPairEd25519(signaturePair.getPubkey()) + const signature = signaturePair.getSignature() + if (!signature) { + throw new LogError('missing signature') + } + return publicKeyPair.verify(new MemoryBlock(message), signature) + } + + private createSecretBox(salt: string): SecretKeyCryptography { + if (!CONFIG.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD) { + throw new LogError( + 'missing GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD in env or config', + ) + } + const secretBox = new SecretKeyCryptography() + secretBox.createKey(salt, CONFIG.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD) + return secretBox } } diff --git a/dlt-connector/src/data/Mnemonic.ts b/dlt-connector/src/data/Mnemonic.ts deleted file mode 100644 index e23864e60..000000000 --- a/dlt-connector/src/data/Mnemonic.ts +++ /dev/null @@ -1,48 +0,0 @@ -// https://www.npmjs.com/package/bip39 -import { entropyToMnemonic, mnemonicToSeedSync } from 'bip39' -// eslint-disable-next-line camelcase -import { randombytes_buf } from 'sodium-native' - -import { LogError } from '@/server/LogError' - -export class Mnemonic { - private _passphrase = '' - public constructor(seed?: Buffer | string) { - if (seed) { - Mnemonic.validateSeed(seed) - this._passphrase = entropyToMnemonic(seed) - return - } - const entropy = Buffer.alloc(256) - randombytes_buf(entropy) - this._passphrase = entropyToMnemonic(entropy) - } - - public get passphrase(): string { - return this._passphrase - } - - public get seed(): Buffer { - return mnemonicToSeedSync(this._passphrase) - } - - public static validateSeed(seed: Buffer | string): void { - let seedBuffer: Buffer - if (!Buffer.isBuffer(seed)) { - seedBuffer = Buffer.from(seed, 'hex') - } else { - seedBuffer = seed - } - if (seedBuffer.length < 16 || seedBuffer.length > 32 || seedBuffer.length % 4 !== 0) { - throw new LogError( - 'invalid seed, must be in binary between 16 and 32 Bytes, Power of 4, for more infos: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#generating-the-mnemonic', - { - seedBufferHex: seedBuffer.toString('hex'), - toShort: seedBuffer.length < 16, - toLong: seedBuffer.length > 32, - powerOf4: seedBuffer.length % 4, - }, - ) - } - } -} diff --git a/dlt-connector/src/data/Transaction.builder.ts b/dlt-connector/src/data/Transaction.builder.ts index f46f02a29..a07ed8589 100644 --- a/dlt-connector/src/data/Transaction.builder.ts +++ b/dlt-connector/src/data/Transaction.builder.ts @@ -1,18 +1,17 @@ import { Account } from '@entity/Account' import { Community } from '@entity/Community' import { Transaction } from '@entity/Transaction' +import { + GradidoTransaction, + InteractionSerialize, + InteractionToJson, + TransactionBody, +} from 'gradido-blockchain-js' -import { GradidoTransaction } from '@/data/proto/3_3/GradidoTransaction' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { LogError } from '@/server/LogError' -import { bodyBytesToTransactionBody, transactionBodyToBodyBytes } from '@/utils/typeConverter' -import { AccountRepository } from './Account.repository' -import { BackendTransactionFactory } from './BackendTransaction.factory' import { CommunityRepository } from './Community.repository' -import { TransactionBodyBuilder } from './proto/TransactionBody.builder' export class TransactionBuilder { private transaction: Transaction @@ -97,16 +96,6 @@ export class TransactionBuilder { return this } - public addBackendTransaction(transactionDraft: TransactionDraft): TransactionBuilder { - if (!this.transaction.backendTransactions) { - this.transaction.backendTransactions = [] - } - this.transaction.backendTransactions.push( - BackendTransactionFactory.createFromTransactionDraft(transactionDraft), - ) - return this - } - public async setCommunityFromUser(user: UserIdentifier): Promise { // get sender community const community = await CommunityRepository.getCommunityForUserIdentifier(user) @@ -122,58 +111,43 @@ export class TransactionBuilder { return this.setOtherCommunity(otherCommunity) } - public async fromGradidoTransactionSearchForAccounts( - gradidoTransaction: GradidoTransaction, - ): Promise { - this.transaction.bodyBytes = Buffer.from(gradidoTransaction.bodyBytes) - const transactionBody = bodyBytesToTransactionBody(this.transaction.bodyBytes) - this.fromTransactionBody(transactionBody) - - const firstSigPair = gradidoTransaction.getFirstSignature() - // TODO: adapt if transactions with more than one signatures where added - - // get recipient and signer accounts if not already set - this.transaction.signingAccount ??= await AccountRepository.findAccountByPublicKey( - firstSigPair.pubKey, - ) - this.transaction.recipientAccount ??= await AccountRepository.findAccountByPublicKey( - transactionBody.getRecipientPublicKey(), - ) - this.transaction.signature = Buffer.from(firstSigPair.signature) - - return this + public fromGradidoTransaction(transaction: GradidoTransaction): TransactionBuilder { + const body = transaction.getTransactionBody() + if (!body) { + throw new LogError('missing transaction body on Gradido Transaction') + } + // set first signature + const firstSignature = transaction.getSignatureMap().getSignaturePairs().get(0).getSignature() + if (!firstSignature) { + throw new LogError('error missing first signature') + } + this.transaction.signature = firstSignature.data() + return this.fromTransactionBody(body, transaction.getBodyBytes()?.data()) } - public fromGradidoTransaction(gradidoTransaction: GradidoTransaction): TransactionBuilder { - this.transaction.bodyBytes = Buffer.from(gradidoTransaction.bodyBytes) - const transactionBody = bodyBytesToTransactionBody(this.transaction.bodyBytes) - this.fromTransactionBody(transactionBody) - - const firstSigPair = gradidoTransaction.getFirstSignature() - // TODO: adapt if transactions with more than one signatures where added - this.transaction.signature = Buffer.from(firstSigPair.signature) - - return this - } - - public fromTransactionBody(transactionBody: TransactionBody): TransactionBuilder { - transactionBody.fillTransactionRecipe(this.transaction) - this.transaction.bodyBytes ??= transactionBodyToBodyBytes(transactionBody) - return this - } - - public fromTransactionBodyBuilder( - transactionBodyBuilder: TransactionBodyBuilder, + public fromTransactionBody( + transactionBody: TransactionBody, + bodyBytes: Buffer | null | undefined, ): TransactionBuilder { - const signingAccount = transactionBodyBuilder.getSigningAccount() - if (signingAccount) { - this.setSigningAccount(signingAccount) + if (!bodyBytes) { + bodyBytes = new InteractionSerialize(transactionBody).run()?.data() } - const recipientAccount = transactionBodyBuilder.getRecipientAccount() - if (recipientAccount) { - this.setRecipientAccount(recipientAccount) + if (!bodyBytes) { + throw new LogError( + 'cannot serialize TransactionBody', + JSON.parse(new InteractionToJson(transactionBody).run()), + ) } - this.fromTransactionBody(transactionBodyBuilder.getTransactionBody()) + this.transaction.type = transactionBody.getTransactionType() + this.transaction.createdAt = new Date(transactionBody.getCreatedAt().getDate()) + this.transaction.protocolVersion = transactionBody.getVersionNumber() + + const transferAmount = transactionBody.getTransferAmount() + this.transaction.amount = transferAmount + ? transferAmount.getAmount().getGradidoCent() + : undefined + + this.transaction.bodyBytes ??= bodyBytes return this } } diff --git a/dlt-connector/src/data/Transaction.logic.test.ts b/dlt-connector/src/data/Transaction.logic.test.ts deleted file mode 100644 index b5ef73de2..000000000 --- a/dlt-connector/src/data/Transaction.logic.test.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' -import { Decimal } from 'decimal.js-light' - -import { logger } from '@/logging/logger' - -import { CommunityRoot } from './proto/3_3/CommunityRoot' -import { CrossGroupType } from './proto/3_3/enum/CrossGroupType' -import { GradidoCreation } from './proto/3_3/GradidoCreation' -import { GradidoDeferredTransfer } from './proto/3_3/GradidoDeferredTransfer' -import { GradidoTransfer } from './proto/3_3/GradidoTransfer' -import { RegisterAddress } from './proto/3_3/RegisterAddress' -import { TransactionBody } from './proto/3_3/TransactionBody' -import { TransactionLogic } from './Transaction.logic' - -let a: Transaction -let b: Transaction - -describe('data/transaction.logic', () => { - describe('isBelongTogether', () => { - beforeEach(() => { - const now = new Date() - let body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.transfer = new GradidoTransfer() - body.otherGroup = 'recipient group' - - a = new Transaction() - a.community = new Community() - a.communityId = 1 - a.otherCommunityId = 2 - a.id = 1 - a.signingAccountId = 1 - a.recipientAccountId = 2 - a.createdAt = now - a.amount = new Decimal('100') - a.signature = Buffer.alloc(64) - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - - body = new TransactionBody() - body.type = CrossGroupType.INBOUND - body.transfer = new GradidoTransfer() - body.otherGroup = 'sending group' - - b = new Transaction() - b.community = new Community() - b.communityId = 2 - b.otherCommunityId = 1 - b.id = 2 - b.signingAccountId = 1 - b.recipientAccountId = 2 - b.createdAt = now - b.amount = new Decimal('100') - b.signature = Buffer.alloc(64) - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - }) - - const spy = jest.spyOn(logger, 'info') - - it('true', () => { - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(true) - }) - - it('false because of same id', () => { - b.id = 1 - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('id is the same, it is the same transaction!') - }) - - it('false because of different signing accounts', () => { - b.signingAccountId = 17 - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - 'transaction a and b are not pairs', - expect.objectContaining({}), - ) - }) - - it('false because of different recipient accounts', () => { - b.recipientAccountId = 21 - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - 'transaction a and b are not pairs', - expect.objectContaining({}), - ) - }) - - it('false because of different community ids', () => { - b.communityId = 6 - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - 'transaction a and b are not pairs', - expect.objectContaining({}), - ) - }) - - it('false because of different other community ids', () => { - b.otherCommunityId = 3 - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - 'transaction a and b are not pairs', - expect.objectContaining({}), - ) - }) - - it('false because of different createdAt', () => { - b.createdAt = new Date('2021-01-01T17:12') - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - 'transaction a and b are not pairs', - expect.objectContaining({}), - ) - }) - - describe('false because of mismatching cross group type', () => { - const body = new TransactionBody() - it('a is LOCAL', () => { - body.type = CrossGroupType.LOCAL - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenNthCalledWith(7, 'no one can be LOCAL') - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('b is LOCAL', () => { - body.type = CrossGroupType.LOCAL - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenNthCalledWith(9, 'no one can be LOCAL') - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('both are INBOUND', () => { - body.type = CrossGroupType.INBOUND - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('both are OUTBOUND', () => { - body.type = CrossGroupType.OUTBOUND - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('a is CROSS', () => { - body.type = CrossGroupType.CROSS - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('b is CROSS', () => { - body.type = CrossGroupType.CROSS - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "cross group types don't match", - expect.objectContaining({}), - ) - }) - - it('true with a as INBOUND and b as OUTBOUND', () => { - let body = TransactionBody.fromBodyBytes(a.bodyBytes) - body.type = CrossGroupType.INBOUND - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - body = TransactionBody.fromBodyBytes(b.bodyBytes) - body.type = CrossGroupType.OUTBOUND - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(true) - }) - }) - - describe('false because of transaction type not suitable for cross group transactions', () => { - const body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - it('without transaction type (broken TransactionBody)', () => { - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(() => logic.isBelongTogether(b)).toThrowError("couldn't determine transaction type") - }) - - it('not the same transaction types', () => { - const body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.registerAddress = new RegisterAddress() - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "transaction types don't match", - expect.objectContaining({}), - ) - }) - - it('community root cannot be a cross group transaction', () => { - let body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.communityRoot = new CommunityRoot() - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - body = new TransactionBody() - body.type = CrossGroupType.INBOUND - body.communityRoot = new CommunityRoot() - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "TransactionType COMMUNITY_ROOT couldn't be a CrossGroup Transaction", - ) - }) - - it('Gradido Creation cannot be a cross group transaction', () => { - let body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.creation = new GradidoCreation() - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - body = new TransactionBody() - body.type = CrossGroupType.INBOUND - body.creation = new GradidoCreation() - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "TransactionType GRADIDO_CREATION couldn't be a CrossGroup Transaction", - ) - }) - - it('Deferred Transfer cannot be a cross group transaction', () => { - let body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.deferredTransfer = new GradidoDeferredTransfer() - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - body = new TransactionBody() - body.type = CrossGroupType.INBOUND - body.deferredTransfer = new GradidoDeferredTransfer() - b.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith( - "TransactionType GRADIDO_DEFERRED_TRANSFER couldn't be a CrossGroup Transaction", - ) - }) - }) - - describe('false because of wrong amount', () => { - it('amount missing on a', () => { - a.amount = undefined - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('missing amount') - }) - - it('amount missing on b', () => { - b.amount = undefined - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('missing amount') - }) - - it('amount not the same', () => { - a.amount = new Decimal('101') - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('amounts mismatch', expect.objectContaining({})) - }) - }) - - it('false because otherGroup are the same', () => { - const body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.transfer = new GradidoTransfer() - body.otherGroup = 'sending group' - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('otherGroups are the same', expect.objectContaining({})) - }) - - it('false because of different memos', () => { - const body = new TransactionBody() - body.type = CrossGroupType.OUTBOUND - body.transfer = new GradidoTransfer() - body.otherGroup = 'recipient group' - body.memo = 'changed memo' - a.bodyBytes = Buffer.from(TransactionBody.encode(body).finish()) - const logic = new TransactionLogic(a) - expect(logic.isBelongTogether(b)).toBe(false) - expect(spy).toHaveBeenLastCalledWith('memo differ', expect.objectContaining({})) - }) - }) -}) diff --git a/dlt-connector/src/data/Transaction.logic.ts b/dlt-connector/src/data/Transaction.logic.ts deleted file mode 100644 index c62f78f50..000000000 --- a/dlt-connector/src/data/Transaction.logic.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { Transaction } from '@entity/Transaction' -import { Not } from 'typeorm' - -import { logger } from '@/logging/logger' -import { TransactionBodyLoggingView } from '@/logging/TransactionBodyLogging.view' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' -import { LogError } from '@/server/LogError' - -import { CrossGroupType } from './proto/3_3/enum/CrossGroupType' -import { TransactionType } from './proto/3_3/enum/TransactionType' -import { TransactionBody } from './proto/3_3/TransactionBody' - -export class TransactionLogic { - protected transactionBody: TransactionBody | undefined - - // eslint-disable-next-line no-useless-constructor - public constructor(private self: Transaction) {} - - /** - * search for transaction pair for Cross Group Transaction - * @returns - */ - public async findPairTransaction(): Promise { - const type = this.getBody().type - if (type === CrossGroupType.LOCAL) { - throw new LogError("local transaction don't has a pairing transaction") - } - - // check if already was loaded from db - if (this.self.pairingTransaction) { - return this.self.pairingTransaction - } - - if (this.self.pairingTransaction) { - const pairingTransaction = await Transaction.findOneBy({ id: this.self.pairingTransaction }) - if (pairingTransaction) { - return pairingTransaction - } - } - // check if we find some in db - const sameCreationDateTransactions = await Transaction.findBy({ - createdAt: this.self.createdAt, - id: Not(this.self.id), - }) - if ( - sameCreationDateTransactions.length === 1 && - this.isBelongTogether(sameCreationDateTransactions[0]) - ) { - return sameCreationDateTransactions[0] - } - // this approach only work if all entities get ids really incremented by one - if (type === CrossGroupType.OUTBOUND) { - const prevTransaction = await Transaction.findOneBy({ id: this.self.id - 1 }) - if (prevTransaction && this.isBelongTogether(prevTransaction)) { - return prevTransaction - } - } else if (type === CrossGroupType.INBOUND) { - const nextTransaction = await Transaction.findOneBy({ id: this.self.id + 1 }) - if (nextTransaction && this.isBelongTogether(nextTransaction)) { - return nextTransaction - } - } - throw new LogError("couldn't find valid pairing transaction", { - id: this.self.id, - type: CrossGroupType[type], - transactionCountWithSameCreatedAt: sameCreationDateTransactions.length, - }) - } - - /** - * check if two transactions belong together - * are they pairs for a cross group transaction - * @param otherTransaction - */ - public isBelongTogether(otherTransaction: Transaction): boolean { - if (this.self.id === otherTransaction.id) { - logger.info('id is the same, it is the same transaction!') - return false - } - - if ( - this.self.signingAccountId !== otherTransaction.signingAccountId || - this.self.recipientAccountId !== otherTransaction.recipientAccountId || - this.self.communityId !== otherTransaction.otherCommunityId || - this.self.otherCommunityId !== otherTransaction.communityId || - this.self.createdAt.getTime() !== otherTransaction.createdAt.getTime() - ) { - logger.info('transaction a and b are not pairs', { - a: new TransactionLoggingView(this.self).toJSON(), - b: new TransactionLoggingView(otherTransaction).toJSON(), - }) - return false - } - const body = this.getBody() - const otherBody = TransactionBody.fromBodyBytes(otherTransaction.bodyBytes) - /** - * both must be Cross or - * one can be OUTBOUND and one can be INBOUND - * no one can be LOCAL - */ - - if (!this.validCrossGroupTypes(body.type, otherBody.type)) { - logger.info("cross group types don't match", { - a: new TransactionBodyLoggingView(body).toJSON(), - b: new TransactionBodyLoggingView(otherBody).toJSON(), - }) - return false - } - const type = body.getTransactionType() - const otherType = otherBody.getTransactionType() - if (!type || !otherType) { - throw new LogError("couldn't determine transaction type", { - a: new TransactionBodyLoggingView(body).toJSON(), - b: new TransactionBodyLoggingView(otherBody).toJSON(), - }) - } - if (type !== otherType) { - logger.info("transaction types don't match", { - a: new TransactionBodyLoggingView(body).toJSON(), - b: new TransactionBodyLoggingView(otherBody).toJSON(), - }) - return false - } - if ( - [ - TransactionType.COMMUNITY_ROOT, - TransactionType.GRADIDO_CREATION, - TransactionType.GRADIDO_DEFERRED_TRANSFER, - ].includes(type) - ) { - logger.info(`TransactionType ${TransactionType[type]} couldn't be a CrossGroup Transaction`) - return false - } - if ( - [ - TransactionType.GRADIDO_CREATION, - TransactionType.GRADIDO_TRANSFER, - TransactionType.GRADIDO_DEFERRED_TRANSFER, - ].includes(type) - ) { - if (!this.self.amount || !otherTransaction.amount) { - logger.info('missing amount') - return false - } - if (this.self.amount.cmp(otherTransaction.amount.toString())) { - logger.info('amounts mismatch', { - a: this.self.amount.toString(), - b: otherTransaction.amount.toString(), - }) - return false - } - } - if (body.otherGroup === otherBody.otherGroup) { - logger.info('otherGroups are the same', { - a: new TransactionBodyLoggingView(body).toJSON(), - b: new TransactionBodyLoggingView(otherBody).toJSON(), - }) - return false - } - if (body.memo !== otherBody.memo) { - logger.info('memo differ', { - a: new TransactionBodyLoggingView(body).toJSON(), - b: new TransactionBodyLoggingView(otherBody).toJSON(), - }) - return false - } - return true - } - - /** - * both must be CROSS or - * one can be OUTBOUND and one can be INBOUND - * no one can be LOCAL - * @return true if crossGroupTypes are valid - */ - protected validCrossGroupTypes(a: CrossGroupType, b: CrossGroupType): boolean { - logger.debug('compare ', { - a: CrossGroupType[a], - b: CrossGroupType[b], - }) - if (a === CrossGroupType.LOCAL || b === CrossGroupType.LOCAL) { - logger.info('no one can be LOCAL') - return false - } - if ( - (a === CrossGroupType.INBOUND && b === CrossGroupType.OUTBOUND) || - (a === CrossGroupType.OUTBOUND && b === CrossGroupType.INBOUND) - ) { - return true // One can be INBOUND and one can be OUTBOUND - } - return a === CrossGroupType.CROSS && b === CrossGroupType.CROSS - } - - public getBody(): TransactionBody { - if (!this.transactionBody) { - this.transactionBody = TransactionBody.fromBodyBytes(this.self.bodyBytes) - } - return this.transactionBody - } -} diff --git a/dlt-connector/src/data/proto/3_3/CommunityRoot.ts b/dlt-connector/src/data/proto/3_3/CommunityRoot.ts deleted file mode 100644 index c03460741..000000000 --- a/dlt-connector/src/data/proto/3_3/CommunityRoot.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' -import { Field, Message } from 'protobufjs' - -import { AbstractTransaction } from '../AbstractTransaction' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class CommunityRoot extends Message implements AbstractTransaction { - public constructor(community?: Community) { - if (community) { - super({ - rootPubkey: community.rootPubkey, - gmwPubkey: community.gmwAccount?.derive2Pubkey, - aufPubkey: community.aufAccount?.derive2Pubkey, - }) - } else { - super() - } - } - - @Field.d(1, 'bytes') - public rootPubkey: Buffer - - // community public budget account - @Field.d(2, 'bytes') - public gmwPubkey: Buffer - - // community compensation and environment founds account - @Field.d(3, 'bytes') - public aufPubkey: Buffer - - // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars - public fillTransactionRecipe(recipe: Transaction): void {} -} diff --git a/dlt-connector/src/data/proto/3_3/ConfirmedTransaction.ts b/dlt-connector/src/data/proto/3_3/ConfirmedTransaction.ts deleted file mode 100644 index d59b991e8..000000000 --- a/dlt-connector/src/data/proto/3_3/ConfirmedTransaction.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Field, Message } from 'protobufjs' - -import { base64ToBuffer } from '@/utils/typeConverter' - -import { GradidoTransaction } from './GradidoTransaction' -import { TimestampSeconds } from './TimestampSeconds' - -/* - id will be set by Node server - running_hash will be also set by Node server, - calculated from previous transaction running_hash and this id, transaction and received -*/ - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class ConfirmedTransaction extends Message { - static fromBase64(base64: string): ConfirmedTransaction { - return ConfirmedTransaction.decode(new Uint8Array(base64ToBuffer(base64))) - } - - @Field.d(1, 'uint64') - id: Long - - @Field.d(2, 'GradidoTransaction') - transaction: GradidoTransaction - - @Field.d(3, 'TimestampSeconds') - confirmedAt: TimestampSeconds - - @Field.d(4, 'string') - versionNumber: string - - @Field.d(5, 'bytes') - runningHash: Buffer - - @Field.d(6, 'bytes') - messageId: Buffer - - @Field.d(7, 'string') - accountBalance: string -} diff --git a/dlt-connector/src/data/proto/3_3/GradidoCreation.test.ts b/dlt-connector/src/data/proto/3_3/GradidoCreation.test.ts deleted file mode 100644 index 06011838c..000000000 --- a/dlt-connector/src/data/proto/3_3/GradidoCreation.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import 'reflect-metadata' -import { TransactionErrorType } from '@enum/TransactionErrorType' - -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - -import { GradidoCreation } from './GradidoCreation' - -describe('proto/3.3/GradidoCreation', () => { - it('test with missing targetDate', () => { - const transactionDraft = new TransactionDraft() - expect(() => { - // eslint-disable-next-line no-new - new GradidoCreation(transactionDraft) - }).toThrowError( - new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing targetDate for contribution', - ), - ) - }) -}) diff --git a/dlt-connector/src/data/proto/3_3/GradidoCreation.ts b/dlt-connector/src/data/proto/3_3/GradidoCreation.ts deleted file mode 100644 index 0fa08eff5..000000000 --- a/dlt-connector/src/data/proto/3_3/GradidoCreation.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Account } from '@entity/Account' -import { Transaction } from '@entity/Transaction' -import { Decimal } from 'decimal.js-light' -import { Field, Message } from 'protobufjs' - -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - -import { AbstractTransaction } from '../AbstractTransaction' - -import { TimestampSeconds } from './TimestampSeconds' -import { TransferAmount } from './TransferAmount' - -// need signature from group admin or -// percent of group users another than the receiver -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class GradidoCreation extends Message implements AbstractTransaction { - constructor(transaction?: TransactionDraft, recipientAccount?: Account) { - if (transaction) { - if (!transaction.targetDate) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing targetDate for contribution', - ) - } - super({ - recipient: new TransferAmount({ - amount: transaction.amount.toString(), - pubkey: recipientAccount?.derive2Pubkey, - }), - targetDate: new TimestampSeconds(new Date(transaction.targetDate)), - }) - } else { - super() - } - } - - // recipient: TransferAmount contain - // - recipient public key - // - amount - // - communityId // only set if not the same as recipient community - @Field.d(1, TransferAmount) - public recipient: TransferAmount - - @Field.d(3, 'TimestampSeconds') - public targetDate: TimestampSeconds - - public fillTransactionRecipe(recipe: Transaction): void { - recipe.amount = new Decimal(this.recipient.amount ?? 0) - } -} diff --git a/dlt-connector/src/data/proto/3_3/GradidoDeferredTransfer.ts b/dlt-connector/src/data/proto/3_3/GradidoDeferredTransfer.ts deleted file mode 100644 index f48719b16..000000000 --- a/dlt-connector/src/data/proto/3_3/GradidoDeferredTransfer.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Transaction } from '@entity/Transaction' -import Decimal from 'decimal.js-light' -import { Field, Message } from 'protobufjs' - -import { AbstractTransaction } from '../AbstractTransaction' - -import { GradidoTransfer } from './GradidoTransfer' -import { TimestampSeconds } from './TimestampSeconds' - -// transaction type for chargeable transactions -// for transaction for people which haven't a account already -// consider using a seed number for key pair generation for recipient -// using seed as redeem key for claiming transaction, technically make a default Transfer transaction from recipient address -// seed must be long enough to prevent brute force, maybe base64 encoded -// to own account -// https://www.npmjs.com/package/@apollo/protobufjs -export class GradidoDeferredTransfer - // eslint-disable-next-line no-use-before-define - extends Message - implements AbstractTransaction -{ - // amount is amount with decay for time span between transaction was received and timeout - // useable amount can be calculated - // recipient address don't need to be registered in blockchain with register address - @Field.d(1, GradidoTransfer) - public transfer: GradidoTransfer - - // if timeout timestamp is reached if it wasn't used, it will be booked back minus decay - // technically on blockchain no additional transaction will be created because how should sign it? - // the decay for amount and the seconds until timeout is lost no matter what happened - // consider is as fee for this service - // rest decay could be transferred back as separate transaction - @Field.d(2, 'TimestampSeconds') - public timeout: TimestampSeconds - - // split for n recipient - // max gradido per recipient? or per transaction with cool down? - - public fillTransactionRecipe(recipe: Transaction): void { - recipe.amount = new Decimal(this.transfer.sender.amount ?? 0) - } -} diff --git a/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts b/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts deleted file mode 100644 index f4274407b..000000000 --- a/dlt-connector/src/data/proto/3_3/GradidoTransaction.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Field, Message } from 'protobufjs' - -import { LogError } from '@/server/LogError' - -import { SignatureMap } from './SignatureMap' -import { SignaturePair } from './SignaturePair' -import { TransactionBody } from './TransactionBody' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class GradidoTransaction extends Message { - constructor(body?: TransactionBody) { - if (body) { - super({ - sigMap: new SignatureMap(), - bodyBytes: Buffer.from(TransactionBody.encode(body).finish()), - }) - } else { - super() - } - } - - @Field.d(1, SignatureMap) - public sigMap: SignatureMap - - // inspired by Hedera - // bodyBytes are the payload for signature - // bodyBytes are serialized TransactionBody - @Field.d(2, 'bytes') - public bodyBytes: Buffer - - // if it is a cross group transaction the parent message - // id from outbound transaction or other by cross - @Field.d(3, 'bytes') - public parentMessageId?: Buffer - - getFirstSignature(): SignaturePair { - const sigPair = this.sigMap.sigPair - if (sigPair.length !== 1) { - throw new LogError("signature count don't like expected") - } - return sigPair[0] - } - - getTransactionBody(): TransactionBody { - return TransactionBody.fromBodyBytes(this.bodyBytes) - } -} diff --git a/dlt-connector/src/data/proto/3_3/GradidoTransfer.ts b/dlt-connector/src/data/proto/3_3/GradidoTransfer.ts deleted file mode 100644 index 7e9da40bd..000000000 --- a/dlt-connector/src/data/proto/3_3/GradidoTransfer.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Account } from '@entity/Account' -import { Transaction } from '@entity/Transaction' -import Decimal from 'decimal.js-light' -import { Field, Message } from 'protobufjs' - -import { TransactionDraft } from '@/graphql/input/TransactionDraft' - -import { AbstractTransaction } from '../AbstractTransaction' - -import { TransferAmount } from './TransferAmount' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class GradidoTransfer extends Message implements AbstractTransaction { - constructor( - transaction?: TransactionDraft, - signingAccount?: Account, - recipientAccount?: Account, - coinOrigin?: string, - ) { - if (transaction) { - super({ - sender: new TransferAmount({ - amount: transaction.amount.toString(), - pubkey: signingAccount?.derive2Pubkey, - communityId: coinOrigin, - }), - recipient: recipientAccount?.derive2Pubkey, - }) - } else { - super() - } - } - - // sender: TransferAmount contain - // - sender public key - // - amount - // - communityId // only set if not the same as sender and recipient community - @Field.d(1, TransferAmount) - public sender: TransferAmount - - // the recipient public key - @Field.d(2, 'bytes') - public recipient: Buffer - - public fillTransactionRecipe(recipe: Transaction): void { - recipe.amount = new Decimal(this.sender?.amount ?? 0) - } -} diff --git a/dlt-connector/src/data/proto/3_3/GroupFriendsUpdate.ts b/dlt-connector/src/data/proto/3_3/GroupFriendsUpdate.ts deleted file mode 100644 index b64e80a73..000000000 --- a/dlt-connector/src/data/proto/3_3/GroupFriendsUpdate.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { Transaction } from '@entity/Transaction' -import { Field, Message } from 'protobufjs' - -import { AbstractTransaction } from '../AbstractTransaction' - -// connect group together -// only CrossGroupType CROSS (in TransactionBody) -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class GroupFriendsUpdate extends Message implements AbstractTransaction { - // if set to true, colors of this both groups are trait as the same - // on creation user get coins still in there color - // on transfer into another group which a connection exist, - // coins will be automatic swapped into user group color coin - // (if fusion between src coin and dst coin is enabled) - @Field.d(1, 'bool') - public colorFusion: boolean - - public fillTransactionRecipe(recipe: Transaction): void { - throw new Error('Method not implemented.') - } -} diff --git a/dlt-connector/src/data/proto/3_3/RegisterAddress.ts b/dlt-connector/src/data/proto/3_3/RegisterAddress.ts deleted file mode 100644 index 08cb39868..000000000 --- a/dlt-connector/src/data/proto/3_3/RegisterAddress.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { Account } from '@entity/Account' -import { Transaction } from '@entity/Transaction' -import { User } from '@entity/User' -import { Field, Message } from 'protobufjs' - -import { AddressType } from '@/data/proto/3_3/enum/AddressType' -import { AccountType } from '@/graphql/enum/AccountType' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { accountTypeToAddressType } from '@/utils/typeConverter' - -import { AbstractTransaction } from '../AbstractTransaction' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class RegisterAddress extends Message implements AbstractTransaction { - constructor(transaction?: UserAccountDraft, account?: Account) { - if (transaction) { - super({ addressType: accountTypeToAddressType(transaction.accountType) }) - if (account) { - this.derivationIndex = account.derivationIndex - this.accountPubkey = account.derive2Pubkey - if (account.user) { - this.userPubkey = account.user.derive1Pubkey - } - } - } else { - super() - } - } - - @Field.d(1, 'bytes') - public userPubkey: Buffer - - @Field.d(2, AddressType) - public addressType: AddressType - - @Field.d(3, 'bytes') - public nameHash: Buffer - - @Field.d(4, 'bytes') - public accountPubkey: Buffer - - @Field.d(5, 'uint32') - public derivationIndex?: number - - public fillTransactionRecipe(_recipe: Transaction): void {} -} diff --git a/dlt-connector/src/data/proto/3_3/SignatureMap.ts b/dlt-connector/src/data/proto/3_3/SignatureMap.ts deleted file mode 100644 index daf69f05f..000000000 --- a/dlt-connector/src/data/proto/3_3/SignatureMap.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Field, Message } from 'protobufjs' - -import { SignaturePair } from './SignaturePair' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class SignatureMap extends Message { - constructor() { - super({ sigPair: [] }) - } - - @Field.d(1, SignaturePair, 'repeated') - public sigPair: SignaturePair[] -} diff --git a/dlt-connector/src/data/proto/3_3/SignaturePair.ts b/dlt-connector/src/data/proto/3_3/SignaturePair.ts deleted file mode 100644 index 80a61a871..000000000 --- a/dlt-connector/src/data/proto/3_3/SignaturePair.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Field, Message } from 'protobufjs' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class SignaturePair extends Message { - @Field.d(1, 'bytes') - public pubKey: Buffer - - @Field.d(2, 'bytes') - public signature: Buffer - - public validate(): boolean { - return this.pubKey.length === 32 && this.signature.length === 64 - } -} diff --git a/dlt-connector/src/data/proto/3_3/Timestamp.test.ts b/dlt-connector/src/data/proto/3_3/Timestamp.test.ts deleted file mode 100644 index 39f6fd2c8..000000000 --- a/dlt-connector/src/data/proto/3_3/Timestamp.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Timestamp } from './Timestamp' - -describe('test timestamp constructor', () => { - it('with date input object', () => { - const now = new Date('2011-04-17T12:01:10.109') - const timestamp = new Timestamp(now) - expect(timestamp.seconds).toEqual(1303041670) - expect(timestamp.nanoSeconds).toEqual(109000000) - }) - - it('with milliseconds number input', () => { - const timestamp = new Timestamp(1303041670109) - expect(timestamp.seconds).toEqual(1303041670) - expect(timestamp.nanoSeconds).toEqual(109000000) - }) -}) diff --git a/dlt-connector/src/data/proto/3_3/Timestamp.ts b/dlt-connector/src/data/proto/3_3/Timestamp.ts deleted file mode 100644 index 91cf06581..000000000 --- a/dlt-connector/src/data/proto/3_3/Timestamp.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Field, Message } from 'protobufjs' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class Timestamp extends Message { - public constructor(input?: Date | number) { - let seconds = 0 - let nanoSeconds = 0 - if (input instanceof Date) { - seconds = Math.floor(input.getTime() / 1000) - nanoSeconds = (input.getTime() % 1000) * 1000000 // Convert milliseconds to nanoseconds - } else if (typeof input === 'number') { - // Calculate seconds and nanoseconds from milliseconds - seconds = Math.floor(input / 1000) - nanoSeconds = (input % 1000) * 1000000 - } - super({ seconds, nanoSeconds }) - } - - // Number of complete seconds since the start of the epoch - @Field.d(1, 'int64') - public seconds: number - - // Number of nanoseconds since the start of the last second - @Field.d(2, 'int32') - public nanoSeconds: number -} diff --git a/dlt-connector/src/data/proto/3_3/TimestampSeconds.test.ts b/dlt-connector/src/data/proto/3_3/TimestampSeconds.test.ts deleted file mode 100644 index 92dc79130..000000000 --- a/dlt-connector/src/data/proto/3_3/TimestampSeconds.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TimestampSeconds } from './TimestampSeconds' - -describe('test TimestampSeconds constructor', () => { - it('with date input object', () => { - const now = new Date('2011-04-17T12:01:10.109') - const timestamp = new TimestampSeconds(now) - expect(timestamp.seconds).toEqual(1303041670) - }) - - it('with milliseconds number input', () => { - const timestamp = new TimestampSeconds(1303041670109) - expect(timestamp.seconds).toEqual(1303041670) - }) -}) diff --git a/dlt-connector/src/data/proto/3_3/TimestampSeconds.ts b/dlt-connector/src/data/proto/3_3/TimestampSeconds.ts deleted file mode 100644 index 6d175c6f3..000000000 --- a/dlt-connector/src/data/proto/3_3/TimestampSeconds.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Field, Message } from 'protobufjs' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class TimestampSeconds extends Message { - public constructor(input?: Date | number) { - let seconds = 0 - // Calculate seconds from milliseconds - if (input instanceof Date) { - seconds = Math.floor(input.getTime() / 1000) - } else if (typeof input === 'number') { - seconds = Math.floor(input / 1000) - } - super({ seconds }) - } - - // Number of complete seconds since the start of the epoch - @Field.d(1, 'int64') - public seconds: number -} diff --git a/dlt-connector/src/data/proto/3_3/TransactionBody.ts b/dlt-connector/src/data/proto/3_3/TransactionBody.ts deleted file mode 100644 index 934e05cfc..000000000 --- a/dlt-connector/src/data/proto/3_3/TransactionBody.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { Transaction } from '@entity/Transaction' -import { Field, Message, OneOf } from 'protobufjs' - -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' -import { timestampToDate } from '@/utils/typeConverter' - -import { AbstractTransaction } from '../AbstractTransaction' -import { determineCrossGroupType, determineOtherGroup } from '../transactionBody.logic' - -import { CommunityRoot } from './CommunityRoot' -import { PROTO_TRANSACTION_BODY_VERSION_NUMBER } from './const' -import { CrossGroupType } from './enum/CrossGroupType' -import { TransactionType } from './enum/TransactionType' -import { GradidoCreation } from './GradidoCreation' -import { GradidoDeferredTransfer } from './GradidoDeferredTransfer' -import { GradidoTransfer } from './GradidoTransfer' -import { GroupFriendsUpdate } from './GroupFriendsUpdate' -import { RegisterAddress } from './RegisterAddress' -import { Timestamp } from './Timestamp' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class TransactionBody extends Message { - public constructor(transaction?: TransactionDraft | CommunityDraft | UserAccountDraft) { - if (transaction) { - let type = CrossGroupType.LOCAL - let otherGroup = '' - if (transaction instanceof TransactionDraft) { - type = determineCrossGroupType(transaction) - otherGroup = determineOtherGroup(type, transaction) - } - - super({ - memo: 'Not implemented yet', - createdAt: new Timestamp(new Date(transaction.createdAt)), - versionNumber: PROTO_TRANSACTION_BODY_VERSION_NUMBER, - type, - otherGroup, - }) - } else { - super() - } - } - - public static fromBodyBytes(bodyBytes: Buffer) { - try { - return TransactionBody.decode(new Uint8Array(bodyBytes)) - } catch (error) { - logger.error('error decoding body from gradido transaction: %s', error) - throw new TransactionError( - TransactionErrorType.PROTO_DECODE_ERROR, - 'cannot decode body from gradido transaction', - ) - } - } - - @Field.d(1, 'string') - public memo: string - - @Field.d(2, Timestamp) - public createdAt: Timestamp - - @Field.d(3, 'string') - public versionNumber: string - - @Field.d(4, CrossGroupType) - public type: CrossGroupType - - @Field.d(5, 'string') - public otherGroup: string - - @OneOf.d( - 'gradidoTransfer', - 'gradidoCreation', - 'groupFriendsUpdate', - 'registerAddress', - 'gradidoDeferredTransfer', - 'communityRoot', - ) - public data: string - - @Field.d(6, 'GradidoTransfer') - transfer?: GradidoTransfer - - @Field.d(7, 'GradidoCreation') - creation?: GradidoCreation - - @Field.d(8, 'GroupFriendsUpdate') - groupFriendsUpdate?: GroupFriendsUpdate - - @Field.d(9, 'RegisterAddress') - registerAddress?: RegisterAddress - - @Field.d(10, 'GradidoDeferredTransfer') - deferredTransfer?: GradidoDeferredTransfer - - @Field.d(11, 'CommunityRoot') - communityRoot?: CommunityRoot - - public getTransactionType(): TransactionType | undefined { - if (this.transfer) return TransactionType.GRADIDO_TRANSFER - else if (this.creation) return TransactionType.GRADIDO_CREATION - else if (this.groupFriendsUpdate) return TransactionType.GROUP_FRIENDS_UPDATE - else if (this.registerAddress) return TransactionType.REGISTER_ADDRESS - else if (this.deferredTransfer) return TransactionType.GRADIDO_DEFERRED_TRANSFER - else if (this.communityRoot) return TransactionType.COMMUNITY_ROOT - } - - // The `TransactionBody` class utilizes Protobuf's `OneOf` field structure which, according to Protobuf documentation - // (https://protobuf.dev/programming-guides/proto3/#oneof), allows only one field within the group to be set at a time. - // Therefore, accessing the `getTransactionDetails()` method returns the first initialized value among the defined fields, - // each of which should be of type AbstractTransaction. It's important to note that due to the nature of Protobuf's `OneOf`, - // only one type from the defined options can be set within the object obtained from Protobuf. - // - // If multiple fields are set in a single object, the method `getTransactionDetails()` will return the first defined value - // based on the order of checks. Developers should handle this behavior according to the expected Protobuf structure. - public getTransactionDetails(): AbstractTransaction | undefined { - if (this.transfer) return this.transfer - if (this.creation) return this.creation - if (this.groupFriendsUpdate) return this.groupFriendsUpdate - if (this.registerAddress) return this.registerAddress - if (this.deferredTransfer) return this.deferredTransfer - if (this.communityRoot) return this.communityRoot - } - - public fillTransactionRecipe(recipe: Transaction): void { - recipe.createdAt = timestampToDate(this.createdAt) - recipe.protocolVersion = this.versionNumber - const transactionType = this.getTransactionType() - if (!transactionType) { - throw new LogError("invalid TransactionBody couldn't determine transaction type") - } - recipe.type = transactionType.valueOf() - this.getTransactionDetails()?.fillTransactionRecipe(recipe) - } - - public getRecipientPublicKey(): Buffer | undefined { - if (this.transfer) { - // this.transfer.recipient contains the publicKey of the recipient - return this.transfer.recipient - } - if (this.creation) { - return this.creation.recipient.pubkey - } - if (this.deferredTransfer) { - // this.deferredTransfer.transfer.recipient contains the publicKey of the recipient - return this.deferredTransfer.transfer.recipient - } - return undefined - } -} diff --git a/dlt-connector/src/data/proto/3_3/TransferAmount.ts b/dlt-connector/src/data/proto/3_3/TransferAmount.ts deleted file mode 100644 index 42da65256..000000000 --- a/dlt-connector/src/data/proto/3_3/TransferAmount.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Field, Message } from 'protobufjs' - -// https://www.npmjs.com/package/@apollo/protobufjs -// eslint-disable-next-line no-use-before-define -export class TransferAmount extends Message { - @Field.d(1, 'bytes') - public pubkey: Buffer - - @Field.d(2, 'string') - public amount: string - - // community which created this coin - // used for colored coins - @Field.d(3, 'string') - public communityId: string -} diff --git a/dlt-connector/src/data/proto/3_3/const.ts b/dlt-connector/src/data/proto/3_3/const.ts deleted file mode 100644 index 9733e14a2..000000000 --- a/dlt-connector/src/data/proto/3_3/const.ts +++ /dev/null @@ -1 +0,0 @@ -export const PROTO_TRANSACTION_BODY_VERSION_NUMBER = '3.3' diff --git a/dlt-connector/src/data/proto/3_3/enum/AddressType.ts b/dlt-connector/src/data/proto/3_3/enum/AddressType.ts deleted file mode 100644 index eace1e022..000000000 --- a/dlt-connector/src/data/proto/3_3/enum/AddressType.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Enum for protobuf - * used from RegisterAddress to determine account type - * master implementation: https://github.com/gradido/gradido_protocol/blob/master/proto/gradido/register_address.proto - */ -export enum AddressType { - NONE = 0, // if no address was found - COMMUNITY_HUMAN = 1, // creation account for human - COMMUNITY_GMW = 2, // community public budget account - COMMUNITY_AUF = 3, // community compensation and environment founds account - COMMUNITY_PROJECT = 4, // no creations allowed - SUBACCOUNT = 5, // no creations allowed - CRYPTO_ACCOUNT = 6, // user control his keys, no creations -} diff --git a/dlt-connector/src/data/proto/3_3/enum/CrossGroupType.ts b/dlt-connector/src/data/proto/3_3/enum/CrossGroupType.ts deleted file mode 100644 index fee592e57..000000000 --- a/dlt-connector/src/data/proto/3_3/enum/CrossGroupType.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Enum for protobuf - * Determine Cross Group type of Transactions - * LOCAL: no cross group transactions, sender and recipient community are the same, only one transaction - * INBOUND: cross group transaction, Inbound part. On recipient community chain. Recipient side by Transfer Transactions - * OUTBOUND: cross group transaction, Outbound part. On sender community chain. Sender side by Transfer Transactions - * CROSS: for cross group transaction which haven't a direction like group friend update - * master implementation: https://github.com/gradido/gradido_protocol/blob/master/proto/gradido/transaction_body.proto - * - * Transaction Handling differ from database focused backend - * In Backend for each transfer transaction there are always two entries in db, - * on for sender user and one for recipient user despite storing basically the same data two times - * In Blockchain Implementation there only two transactions on cross group transactions, one for - * the sender community chain, one for the recipient community chain - * if the transaction stay in the community there is only one transaction - */ -export enum CrossGroupType { - LOCAL = 0, - INBOUND = 1, - OUTBOUND = 2, - CROSS = 3, -} diff --git a/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts b/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts index c50f33bec..07bf5c393 100644 --- a/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts +++ b/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts @@ -4,8 +4,8 @@ * for storing type in db as number */ export enum TransactionType { - GRADIDO_TRANSFER = 1, - GRADIDO_CREATION = 2, + GRADIDO_CREATION = 1, + GRADIDO_TRANSFER = 2, GROUP_FRIENDS_UPDATE = 3, REGISTER_ADDRESS = 4, GRADIDO_DEFERRED_TRANSFER = 5, diff --git a/dlt-connector/src/data/proto/AbstractTransaction.ts b/dlt-connector/src/data/proto/AbstractTransaction.ts deleted file mode 100644 index ac089b096..000000000 --- a/dlt-connector/src/data/proto/AbstractTransaction.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Transaction } from '@entity/Transaction' - -export abstract class AbstractTransaction { - public abstract fillTransactionRecipe(recipe: Transaction): void -} diff --git a/dlt-connector/src/data/proto/TransactionBody.builder.ts b/dlt-connector/src/data/proto/TransactionBody.builder.ts deleted file mode 100644 index cfc1e808b..000000000 --- a/dlt-connector/src/data/proto/TransactionBody.builder.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { Account } from '@entity/Account' -import { Community } from '@entity/Community' - -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { LogError } from '@/server/LogError' - -import { CommunityRoot } from './3_3/CommunityRoot' -import { CrossGroupType } from './3_3/enum/CrossGroupType' -import { GradidoCreation } from './3_3/GradidoCreation' -import { GradidoTransfer } from './3_3/GradidoTransfer' -import { RegisterAddress } from './3_3/RegisterAddress' -import { TransactionBody } from './3_3/TransactionBody' - -export class TransactionBodyBuilder { - private signingAccount?: Account - private recipientAccount?: Account - private body: TransactionBody | undefined - - // https://refactoring.guru/design-patterns/builder/typescript/example - /** - * A fresh builder instance should contain a blank product object, which is - * used in further assembly. - */ - constructor() { - this.reset() - } - - public reset(): void { - this.body = undefined - this.signingAccount = undefined - this.recipientAccount = undefined - } - - /** - * Concrete Builders are supposed to provide their own methods for - * retrieving results. That's because various types of builders may create - * entirely different products that don't follow the same interface. - * Therefore, such methods cannot be declared in the base Builder interface - * (at least in a statically typed programming language). - * - * Usually, after returning the end result to the client, a builder instance - * is expected to be ready to start producing another product. That's why - * it's a usual practice to call the reset method at the end of the - * `getProduct` method body. However, this behavior is not mandatory, and - * you can make your builders wait for an explicit reset call from the - * client code before disposing of the previous result. - */ - public build(): TransactionBody { - const result = this.getTransactionBody() - this.reset() - return result - } - - public getTransactionBody(): TransactionBody { - if (!this.body) { - throw new LogError( - 'cannot build Transaction Body, missing information, please call at least fromTransactionDraft or fromCommunityDraft', - ) - } - return this.body - } - - public getSigningAccount(): Account | undefined { - return this.signingAccount - } - - public getRecipientAccount(): Account | undefined { - return this.recipientAccount - } - - public setSigningAccount(signingAccount: Account): TransactionBodyBuilder { - this.signingAccount = signingAccount - return this - } - - public setRecipientAccount(recipientAccount: Account): TransactionBodyBuilder { - this.recipientAccount = recipientAccount - return this - } - - public setCrossGroupType(type: CrossGroupType): this { - if (!this.body) { - throw new LogError( - 'body is undefined, please call fromTransactionDraft or fromCommunityDraft before', - ) - } - this.body.type = type - return this - } - - public setOtherGroup(otherGroup: string): this { - if (!this.body) { - throw new LogError( - 'body is undefined, please call fromTransactionDraft or fromCommunityDraft before', - ) - } - this.body.otherGroup = otherGroup - return this - } - - public fromUserAccountDraft(userAccountDraft: UserAccountDraft, account: Account): this { - this.body = new TransactionBody(userAccountDraft) - this.body.registerAddress = new RegisterAddress(userAccountDraft, account) - this.body.data = 'registerAddress' - return this - } - - public fromTransactionDraft(transactionDraft: TransactionDraft): TransactionBodyBuilder { - this.body = new TransactionBody(transactionDraft) - // TODO: load public keys for sender and recipient user from db - switch (transactionDraft.type) { - case InputTransactionType.CREATION: - if (!this.recipientAccount) { - throw new LogError('missing recipient account for creation transaction!') - } - this.body.creation = new GradidoCreation(transactionDraft, this.recipientAccount) - this.body.data = 'gradidoCreation' - break - case InputTransactionType.SEND: - case InputTransactionType.RECEIVE: - if (!this.recipientAccount || !this.signingAccount) { - throw new LogError('missing signing and/or recipient account for transfer transaction!') - } - this.body.transfer = new GradidoTransfer( - transactionDraft, - this.signingAccount, - this.recipientAccount, - ) - this.body.data = 'gradidoTransfer' - break - } - return this - } - - public fromCommunityDraft( - communityDraft: CommunityDraft, - community: Community, - ): TransactionBodyBuilder { - this.body = new TransactionBody(communityDraft) - this.body.communityRoot = new CommunityRoot(community) - this.body.data = 'communityRoot' - return this - } -} diff --git a/dlt-connector/src/data/proto/transactionBody.logic.ts b/dlt-connector/src/data/proto/transactionBody.logic.ts deleted file mode 100644 index 69d7e565e..000000000 --- a/dlt-connector/src/data/proto/transactionBody.logic.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - -import { CrossGroupType } from './3_3/enum/CrossGroupType' - -export const determineCrossGroupType = ({ - user, - linkedUser, - type, -}: TransactionDraft): CrossGroupType => { - if ( - !linkedUser.communityUuid || - !user.communityUuid || - linkedUser.communityUuid === '' || - user.communityUuid === '' || - user.communityUuid === linkedUser.communityUuid || - type === InputTransactionType.CREATION - ) { - return CrossGroupType.LOCAL - } else if (type === InputTransactionType.SEND) { - return CrossGroupType.INBOUND - } else if (type === InputTransactionType.RECEIVE) { - return CrossGroupType.OUTBOUND - } - throw new TransactionError( - TransactionErrorType.NOT_IMPLEMENTED_YET, - 'cannot determine CrossGroupType', - ) -} - -export const determineOtherGroup = ( - type: CrossGroupType, - { user, linkedUser }: TransactionDraft, -): string => { - switch (type) { - case CrossGroupType.LOCAL: - return '' - case CrossGroupType.INBOUND: - if (!linkedUser.communityUuid || linkedUser.communityUuid === '') { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing linkedUser community id for cross group transaction', - ) - } - return linkedUser.communityUuid - case CrossGroupType.OUTBOUND: - if (!user.communityUuid || user.communityUuid === '') { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing user community id for cross group transaction', - ) - } - return user.communityUuid - case CrossGroupType.CROSS: - throw new TransactionError(TransactionErrorType.NOT_IMPLEMENTED_YET, 'not implemented yet') - } -} diff --git a/dlt-connector/src/graphql/enum/TransactionErrorType.ts b/dlt-connector/src/graphql/enum/TransactionErrorType.ts index 1b01bc0da..5a8a2a06b 100644 --- a/dlt-connector/src/graphql/enum/TransactionErrorType.ts +++ b/dlt-connector/src/graphql/enum/TransactionErrorType.ts @@ -12,6 +12,7 @@ export enum TransactionErrorType { INVALID_SIGNATURE = 'Invalid Signature', LOGIC_ERROR = 'Logic Error', NOT_FOUND = 'Not found', + VALIDATION_ERROR = 'Validation Error', } registerEnumType(TransactionErrorType, { diff --git a/dlt-connector/src/graphql/model/TransactionRecipe.ts b/dlt-connector/src/graphql/model/TransactionRecipe.ts index 263ccce4a..78fa7fc31 100644 --- a/dlt-connector/src/graphql/model/TransactionRecipe.ts +++ b/dlt-connector/src/graphql/model/TransactionRecipe.ts @@ -7,7 +7,7 @@ import { getEnumValue } from '@/utils/typeConverter' @ObjectType() export class TransactionRecipe { - public constructor({ id, createdAt, type, community }: Transaction) { + public constructor({ id, createdAt, type, community, signature }: Transaction) { const transactionType = getEnumValue(TransactionType, type) if (!transactionType) { throw new LogError('invalid transaction, type is missing') @@ -16,6 +16,7 @@ export class TransactionRecipe { this.createdAt = createdAt.toString() this.type = transactionType.toString() this.topic = community.iotaTopic + this.signatureHex = signature.toString('hex') } @Field(() => Int) @@ -29,4 +30,7 @@ export class TransactionRecipe { @Field(() => String) topic: string + + @Field(() => String) + signatureHex: string } diff --git a/dlt-connector/src/graphql/resolver/CommunityResolver.ts b/dlt-connector/src/graphql/resolver/CommunityResolver.ts index 741de2e6d..dd9db2b23 100644 --- a/dlt-connector/src/graphql/resolver/CommunityResolver.ts +++ b/dlt-connector/src/graphql/resolver/CommunityResolver.ts @@ -1,11 +1,10 @@ -import { Resolver, Query, Arg, Mutation, Args } from 'type-graphql' - import { CommunityArg } from '@arg/CommunityArg' import { TransactionErrorType } from '@enum/TransactionErrorType' import { CommunityDraft } from '@input/CommunityDraft' import { Community } from '@model/Community' import { TransactionError } from '@model/TransactionError' import { TransactionResult } from '@model/TransactionResult' +import { Resolver, Query, Arg, Mutation, Args } from 'type-graphql' import { CommunityRepository } from '@/data/Community.repository' import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 3f34584a9..8302a872f 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -5,12 +5,11 @@ import { TransactionDraft } from '@input/TransactionDraft' import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' import { TransactionRepository } from '@/data/Transaction.repository' import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransactionRecipe.context' -import { BackendTransactionLoggingView } from '@/logging/BackendTransactionLogging.view' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' -import { LogError } from '@/server/LogError' +import { TransactionErrorType } from '../enum/TransactionErrorType' import { TransactionError } from '../model/TransactionError' import { TransactionRecipe } from '../model/TransactionRecipe' import { TransactionResult } from '../model/TransactionResult' @@ -24,30 +23,30 @@ export class TransactionResolver { ): Promise { const createTransactionRecipeContext = new CreateTransactionRecipeContext(transactionDraft) try { - await createTransactionRecipeContext.run() + const result = await createTransactionRecipeContext.run() + if (!result) { + return new TransactionResult( + new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'cannot work with this parameters', + ), + ) + } const transactionRecipe = createTransactionRecipeContext.getTransactionRecipe() // check if a transaction with this signature already exist const existingRecipe = await TransactionRepository.findBySignature( transactionRecipe.signature, ) if (existingRecipe) { - // transaction recipe with this signature already exist, we need only to store the backendTransaction - if (transactionRecipe.backendTransactions.length !== 1) { - throw new LogError('unexpected backend transaction count', { - count: transactionRecipe.backendTransactions.length, - transactionId: transactionRecipe.id, - }) - } - const backendTransaction = transactionRecipe.backendTransactions[0] - backendTransaction.transactionId = transactionRecipe.id - logger.debug( - 'store backendTransaction', - new BackendTransactionLoggingView(backendTransaction), + return new TransactionResult( + new TransactionError( + TransactionErrorType.ALREADY_EXIST, + 'Transaction with same signature already exist', + ), ) - await backendTransaction.save() } else { logger.debug('store transaction recipe', new TransactionLoggingView(transactionRecipe)) - // we can store the transaction and with that automatic the backend transaction + // we store the transaction await transactionRecipe.save() } InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index bfbff10c3..8d140faf3 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,11 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import 'reflect-metadata' +import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' + import { CONFIG } from '@/config' import { BackendClient } from './client/BackendClient' import { CommunityRepository } from './data/Community.repository' -import { Mnemonic } from './data/Mnemonic' import { CommunityDraft } from './graphql/input/CommunityDraft' import { AddCommunityContext } from './interactions/backendToDb/community/AddCommunity.context' import { logger } from './logging/logger' @@ -39,8 +40,22 @@ async function waitForServer( async function main() { if (CONFIG.IOTA_HOME_COMMUNITY_SEED) { - Mnemonic.validateSeed(CONFIG.IOTA_HOME_COMMUNITY_SEED) + try { + const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) + if (seed.size() < 32) { + throw new Error('seed need to be greater than 32 Bytes') + } + } catch (_) { + throw new LogError( + 'IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long', + ) + } } + // load crypto keys for gradido blockchain lib + loadCryptoKeys( + MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), + MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY), + ) // eslint-disable-next-line no-console console.log(`DLT_CONNECTOR_PORT=${CONFIG.DLT_CONNECTOR_PORT}`) const { app } = await createServer() diff --git a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts index ad259b372..050b245e3 100644 --- a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts +++ b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts @@ -18,6 +18,7 @@ import { getDataSource } from '@/typeorm/DataSource' import { CreateTransactionRecipeContext } from '../transaction/CreateTransactionRecipe.context' import { CommunityRole } from './Community.role' +import { TransactionLoggingView } from '@/logging/TransactionLogging.view' export class HomeCommunityRole extends CommunityRole { private transactionRecipe: Transaction diff --git a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts index 89bdbbedf..2b815cd7a 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts @@ -1,9 +1,12 @@ -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' +/* eslint-disable camelcase */ +import { Account } from '@entity/Account' +import { GradidoTransactionBuilder } from 'gradido-blockchain-js' + +import { UserRepository } from '@/data/User.repository' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { TransactionError } from '@/graphql/model/TransactionError' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' export abstract class AbstractTransactionRole { // eslint-disable-next-line no-useless-constructor @@ -11,7 +14,7 @@ export abstract class AbstractTransactionRole { abstract getSigningUser(): UserIdentifier abstract getRecipientUser(): UserIdentifier - abstract getCrossGroupType(): CrossGroupType + abstract getGradidoTransactionBuilder(): Promise public isCrossGroupTransaction(): boolean { return ( @@ -20,44 +23,14 @@ export abstract class AbstractTransactionRole { ) } - /** - * otherGroup is the group/community on which this part of the transaction isn't stored - * Alice from 'gdd1' Send 10 GDD to Bob in 'gdd2' - * OUTBOUND came from sender, stored on sender community blockchain - * OUTBOUND: stored on 'gdd1', otherGroup: 'gdd2' - * INBOUND: goes to receiver, stored on receiver community blockchain - * INBOUND: stored on 'gdd2', otherGroup: 'gdd1' - * @returns iota topic - */ - public getOtherGroup(): string { - let user: UserIdentifier - const type = this.getCrossGroupType() - switch (type) { - case CrossGroupType.LOCAL: - return '' - case CrossGroupType.INBOUND: - user = this.getSigningUser() - if (!user.communityUuid) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing sender/signing user community id for cross group transaction', - ) - } - return iotaTopicFromCommunityUUID(user.communityUuid) - case CrossGroupType.OUTBOUND: - user = this.getRecipientUser() - if (!user.communityUuid) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing recipient user community id for cross group transaction', - ) - } - return iotaTopicFromCommunityUUID(user.communityUuid) - default: - throw new TransactionError( - TransactionErrorType.NOT_IMPLEMENTED_YET, - `type not implemented yet ${type}`, - ) + public async loadUser(user: UserIdentifier): Promise { + const account = await UserRepository.findAccountByUserIdentifier(user) + if (!account) { + throw new TransactionError( + TransactionErrorType.NOT_FOUND, + "couldn't found user account in db", + ) } + return account } } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts b/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts index a4145cd44..659c62c22 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts @@ -1,13 +1,7 @@ -import { Community } from '@entity/Community' - +/* eslint-disable camelcase */ import { AccountLogic } from '@/data/Account.logic' import { KeyPair } from '@/data/KeyPair' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' -import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' -import { UserRepository } from '@/data/User.repository' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' import { AbstractTransactionRole } from './AbstractTransaction.role' import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' @@ -17,62 +11,30 @@ export class BalanceChangingTransactionRecipeRole extends AbstractTransactionRec transactionDraft: TransactionDraft, transactionTypeRole: AbstractTransactionRole, ): Promise { - const signingUser = transactionTypeRole.getSigningUser() - const recipientUser = transactionTypeRole.getRecipientUser() - // loading signing and recipient account - // TODO: look for ways to use only one db call for both - const signingAccount = await UserRepository.findAccountByUserIdentifier(signingUser) - if (!signingAccount) { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, - "couldn't found sender user account in db", - ) - } - const recipientAccount = await UserRepository.findAccountByUserIdentifier(recipientUser) - if (!recipientAccount) { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, - "couldn't found recipient user account in db", - ) - } - // create proto transaction body - const transactionBodyBuilder = new TransactionBodyBuilder() - .setSigningAccount(signingAccount) - .setRecipientAccount(recipientAccount) - .fromTransactionDraft(transactionDraft) - .setCrossGroupType(transactionTypeRole.getCrossGroupType()) - .setOtherGroup(transactionTypeRole.getOtherGroup()) + const signingAccount = await transactionTypeRole.loadUser(transactionTypeRole.getSigningUser()) + const recipientAccount = await transactionTypeRole.loadUser( + transactionTypeRole.getRecipientUser(), + ) + const accountLogic = new AccountLogic(signingAccount) + await this.transactionBuilder.setCommunityFromUser(transactionDraft.user) + const communityKeyPair = new KeyPair(this.transactionBuilder.getCommunity()) + + const gradidoTransactionBuilder = await transactionTypeRole.getGradidoTransactionBuilder() + const transaction = gradidoTransactionBuilder + .setCreatedAt(new Date(transactionDraft.createdAt)) + .sign(accountLogic.calculateKeyPair(communityKeyPair).keyPair) + .build() // build transaction entity this.transactionBuilder - .fromTransactionBodyBuilder(transactionBodyBuilder) - .addBackendTransaction(transactionDraft) + .fromGradidoTransaction(transaction) + .setRecipientAccount(recipientAccount) + .setSigningAccount(signingAccount) - await this.transactionBuilder.setCommunityFromUser(transactionDraft.user) - if (recipientUser.communityUuid !== signingUser.communityUuid) { + if (transactionTypeRole.isCrossGroupTransaction()) { await this.transactionBuilder.setOtherCommunityFromUser(transactionDraft.linkedUser) } - const transaction = this.transactionBuilder.getTransaction() - const communityKeyPair = new KeyPair( - this.getSigningCommunity(transactionTypeRole.getCrossGroupType()), - ) - const accountLogic = new AccountLogic(signingAccount) - // sign - this.transactionBuilder.setSignature( - accountLogic.calculateKeyPair(communityKeyPair).sign(transaction.bodyBytes), - ) return this } - - public getSigningCommunity(crossGroupType: CrossGroupType): Community { - if (crossGroupType === CrossGroupType.INBOUND) { - const otherCommunity = this.transactionBuilder.getOtherCommunity() - if (!otherCommunity) { - throw new TransactionError(TransactionErrorType.NOT_FOUND, 'missing other community') - } - return otherCommunity - } - return this.transactionBuilder.getCommunity() - } } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts index 34d56cce0..cdd953d4c 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts @@ -1,7 +1,9 @@ import { Community } from '@entity/Community' +// eslint-disable-next-line camelcase +import { MemoryBlock, GradidoTransactionBuilder } from 'gradido-blockchain-js' import { KeyPair } from '@/data/KeyPair' -import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' +// import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' @@ -11,15 +13,26 @@ export class CommunityRootTransactionRole extends AbstractTransactionRecipeRole communityDraft: CommunityDraft, community: Community, ): AbstractTransactionRecipeRole { + if ( + !community.rootPubkey || + !community.gmwAccount?.derive2Pubkey || + !community.aufAccount?.derive2Pubkey + ) { + throw new Error('missing one of the public keys for community') + } // create proto transaction body - const transactionBody = new TransactionBodyBuilder() - .fromCommunityDraft(communityDraft, community) + const transaction = new GradidoTransactionBuilder() + .setCommunityRoot( + new MemoryBlock(community.rootPubkey), + new MemoryBlock(community.gmwAccount?.derive2Pubkey), + new MemoryBlock(community.aufAccount?.derive2Pubkey), + ) + .setCreatedAt(new Date(communityDraft.createdAt)) + .sign(new KeyPair(community).keyPair) .build() + // build transaction entity - this.transactionBuilder.fromTransactionBody(transactionBody).setCommunity(community) - const transaction = this.transactionBuilder.getTransaction() - // sign - this.transactionBuilder.setSignature(new KeyPair(community).sign(transaction.bodyBytes)) + this.transactionBuilder.fromGradidoTransaction(transaction).setCommunity(community) return this } } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts index 3d3998db1..a38d9952f 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts @@ -1,18 +1,23 @@ +/* eslint-disable camelcase */ import 'reflect-metadata' import { Account } from '@entity/Account' import { Community } from '@entity/Community' -import { Decimal } from 'decimal.js-light' +import { + AddressType_COMMUNITY_HUMAN, + CrossGroupType_INBOUND, + CrossGroupType_LOCAL, + CrossGroupType_OUTBOUND, + InteractionDeserialize, + MemoryBlock, + TransactionType_CREATION, +} from 'gradido-blockchain-js' import { v4 } from 'uuid' import { TestDB } from '@test/TestDB' import { CONFIG } from '@/config' import { KeyPair } from '@/data/KeyPair' -import { Mnemonic } from '@/data/Mnemonic' -import { AddressType } from '@/data/proto/3_3/enum/AddressType' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' import { AccountType } from '@/graphql/enum/AccountType' import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' @@ -34,9 +39,9 @@ CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa const homeCommunityUuid = v4() const foreignCommunityUuid = v4() -const keyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED)) +const keyPair = new KeyPair(MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED)) const foreignKeyPair = new KeyPair( - new Mnemonic('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'), + MemoryBlock.fromHex('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'), ) let moderator: UserSet @@ -94,16 +99,17 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context derive2Pubkey: firstUser.account.derive2Pubkey, }, }) - - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) - expect(body.registerAddress).toBeDefined() - if (!body.registerAddress) throw new Error() + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() + expect(body?.isRegisterAddress()).toBeTruthy() expect(body).toMatchObject({ - type: CrossGroupType.LOCAL, + type: CrossGroupType_LOCAL, registerAddress: { derivationIndex: 1, - addressType: AddressType.COMMUNITY_HUMAN, + addressType: AddressType_COMMUNITY_HUMAN, }, }) }) @@ -121,9 +127,8 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context await context.run() const transaction = context.getTransactionRecipe() - // console.log(new TransactionLoggingView(transaction)) expect(transaction).toMatchObject({ - type: TransactionType.GRADIDO_CREATION, + type: TransactionType_CREATION, protocolVersion: '3.3', community: { rootPubkey: keyPair.publicKey, @@ -144,15 +149,23 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context ], }) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() // console.log(new TransactionBodyLoggingView(body)) - expect(body.creation).toBeDefined() - if (!body.creation) throw new Error() - const bodyReceiverPubkey = Buffer.from(body.creation.recipient.pubkey) - expect(bodyReceiverPubkey.compare(firstUser.account.derive2Pubkey)).toBe(0) + expect(body?.isCreation()).toBeTruthy() + + expect( + body + ?.getCreation() + ?.getRecipient() + .getPubkey() + ?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), + ).toBeTruthy() expect(body).toMatchObject({ - type: CrossGroupType.LOCAL, + type: CrossGroupType_LOCAL, creation: { recipient: { amount: '2000', @@ -196,16 +209,23 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context ], }) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() // console.log(new TransactionBodyLoggingView(body)) - expect(body.transfer).toBeDefined() - if (!body.transfer) throw new Error() - expect(Buffer.from(body.transfer.recipient).compare(secondUser.account.derive2Pubkey)).toBe(0) - expect(Buffer.from(body.transfer.sender.pubkey).compare(firstUser.account.derive2Pubkey)).toBe( - 0, - ) + expect(body?.isTransfer()).toBeTruthy() + const transfer = body?.getTransfer() + expect(transfer).not.toBeNull() + expect( + transfer?.getRecipient()?.equal(new MemoryBlock(secondUser.account.derive2Pubkey)), + ).toBeTruthy() + expect( + transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), + ).toBeTruthy() + expect(body).toMatchObject({ - type: CrossGroupType.LOCAL, + type: CrossGroupType_LOCAL, transfer: { sender: { amount: '100', @@ -248,16 +268,22 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context ], }) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) - // console.log(new TransactionBodyLoggingView(body)) - expect(body.transfer).toBeDefined() - if (!body.transfer) throw new Error() - expect(Buffer.from(body.transfer.recipient).compare(secondUser.account.derive2Pubkey)).toBe(0) - expect(Buffer.from(body.transfer.sender.pubkey).compare(firstUser.account.derive2Pubkey)).toBe( - 0, - ) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() + expect(body?.isTransfer()).toBeTruthy() + const transfer = body?.getTransfer() + expect(transfer).not.toBeNull() + expect( + transfer?.getRecipient()?.equal(new MemoryBlock(secondUser.account.derive2Pubkey)), + ).toBeTruthy() + expect( + transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), + ).toBeTruthy() + expect(body).toMatchObject({ - type: CrossGroupType.LOCAL, + type: CrossGroupType_LOCAL, transfer: { sender: { amount: '100', @@ -304,16 +330,22 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context }, ], }) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() // console.log(new TransactionBodyLoggingView(body)) - expect(body.transfer).toBeDefined() - if (!body.transfer) throw new Error() - expect(Buffer.from(body.transfer.recipient).compare(foreignUser.account.derive2Pubkey)).toBe(0) - expect(Buffer.from(body.transfer.sender.pubkey).compare(firstUser.account.derive2Pubkey)).toBe( - 0, - ) + expect(body?.isTransfer()).toBeTruthy() + const transfer = body?.getTransfer() + expect(transfer).not.toBeNull() + expect( + transfer?.getRecipient()?.equal(new MemoryBlock(foreignUser.account.derive2Pubkey)), + ).toBeTruthy() + expect( + transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), + ).toBeTruthy() expect(body).toMatchObject({ - type: CrossGroupType.OUTBOUND, + type: CrossGroupType_OUTBOUND, otherGroup: foreignTopic, transfer: { sender: { @@ -361,16 +393,22 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context }, ], }) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() // console.log(new TransactionBodyLoggingView(body)) - expect(body.transfer).toBeDefined() - if (!body.transfer) throw new Error() - expect(Buffer.from(body.transfer.recipient).compare(foreignUser.account.derive2Pubkey)).toBe(0) - expect(Buffer.from(body.transfer.sender.pubkey).compare(firstUser.account.derive2Pubkey)).toBe( - 0, - ) + expect(body?.isTransfer()).toBeTruthy() + const transfer = body?.getTransfer() + expect(transfer).not.toBeNull() + expect( + transfer?.getRecipient()?.equal(new MemoryBlock(foreignUser.account.derive2Pubkey)), + ).toBeTruthy() + expect( + transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), + ).toBeTruthy() expect(body).toMatchObject({ - type: CrossGroupType.INBOUND, + type: CrossGroupType_INBOUND, otherGroup: topic, transfer: { sender: { diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts index eb6d6dffd..10bb3f4f6 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts @@ -14,7 +14,6 @@ import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' import { BalanceChangingTransactionRecipeRole } from './BalanceChangingTransactionRecipeRole' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' -import { ReceiveTransactionRole } from './ReceiveTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { SendTransactionRole } from './SendTransaction.role' @@ -55,8 +54,7 @@ export class CreateTransactionRecipeContext { transactionTypeRole = new SendTransactionRole(this.draft) break case InputTransactionType.RECEIVE: - transactionTypeRole = new ReceiveTransactionRole(this.draft) - break + return false } this.transactionRecipe = await new BalanceChangingTransactionRecipeRole().create( this.draft, diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts index f11518d02..40648b566 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts @@ -1,7 +1,8 @@ +/* eslint-disable camelcase */ import { Community } from '@entity/Community' +import { MemoryBlock, GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' import { CommunityRepository } from '@/data/Community.repository' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { TransactionError } from '@/graphql/model/TransactionError' @@ -19,15 +20,31 @@ export class CreationTransactionRole extends AbstractTransactionRole { return this.self.user } - public getCrossGroupType(): CrossGroupType { - return CrossGroupType.LOCAL + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const recipientUser = await this.loadUser(this.self.user) + if (!this.self.targetDate) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'missing targetDate for contribution', + ) + } + return builder + .setTransactionCreation( + new TransferAmount( + new MemoryBlock(recipientUser.derive2Pubkey), + this.self.amount.toString(), + ), + new Date(this.self.targetDate), + ) + .setMemo('dummy memo for creation') } public async getCommunity(): Promise { if (this.self.user.communityUuid !== this.self.linkedUser.communityUuid) { throw new TransactionError( TransactionErrorType.LOGIC_ERROR, - 'mismatch community uuids on creation transaction', + 'mismatch community uuids on contribution', ) } const community = await CommunityRepository.getCommunityForUserIdentifier(this.self.user) diff --git a/dlt-connector/src/interactions/backendToDb/transaction/ReceiveTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/ReceiveTransaction.role.ts deleted file mode 100644 index bf7c69f0e..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/ReceiveTransaction.role.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' - -import { AbstractTransactionRole } from './AbstractTransaction.role' - -export class ReceiveTransactionRole extends AbstractTransactionRole { - public getSigningUser(): UserIdentifier { - return this.self.linkedUser - } - - public getRecipientUser(): UserIdentifier { - return this.self.user - } - - public getCrossGroupType(): CrossGroupType { - if (this.isCrossGroupTransaction()) { - return CrossGroupType.INBOUND - } - return CrossGroupType.LOCAL - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts index 8b342b1fd..f2a41a72f 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts @@ -1,9 +1,14 @@ import { Account } from '@entity/Account' import { Community } from '@entity/Community' +import { + // eslint-disable-next-line camelcase + AddressType_COMMUNITY_HUMAN, + MemoryBlock, + GradidoTransactionBuilder, +} from 'gradido-blockchain-js' import { AccountLogic } from '@/data/Account.logic' import { CommunityRepository } from '@/data/Community.repository' -import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { TransactionError } from '@/graphql/model/TransactionError' @@ -15,17 +20,32 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRecipeRol userAccountDraft: UserAccountDraft, account: Account, community: Community, - ): Promise { - const bodyBuilder = new TransactionBodyBuilder() + ): Promise { + const user = account.user + if (!user) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'missing user for account') + } + const gradidoTransactionBuilder = new GradidoTransactionBuilder() const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() const signingKeyPair = new AccountLogic(account).calculateKeyPair(communityKeyPair) if (!signingKeyPair) { throw new TransactionError(TransactionErrorType.NOT_FOUND, "couldn't found signing key pair") } + const transaction = gradidoTransactionBuilder + .setRegisterAddress( + new MemoryBlock(user.derive1Pubkey), + AddressType_COMMUNITY_HUMAN, + null, + new MemoryBlock(account.derive2Pubkey), + ) + .setCreatedAt(new Date(userAccountDraft.createdAt)) + .sign(signingKeyPair.keyPair) + .sign(communityKeyPair.keyPair) + .build() + this.transactionBuilder - .fromTransactionBodyBuilder(bodyBuilder.fromUserAccountDraft(userAccountDraft, account)) + .fromGradidoTransaction(transaction) .setCommunity(community) - .setSignature(signingKeyPair.sign(this.transactionBuilder.getTransaction().bodyBytes)) .setSigningAccount(account) return this } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts index 927efdc24..874656cda 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts @@ -1,4 +1,13 @@ -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' +/* eslint-disable camelcase */ +import { + CrossGroupType, + CrossGroupType_LOCAL, + CrossGroupType_OUTBOUND, + MemoryBlock, + GradidoTransactionBuilder, + TransferAmount, +} from 'gradido-blockchain-js' + import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { AbstractTransactionRole } from './AbstractTransaction.role' @@ -12,10 +21,15 @@ export class SendTransactionRole extends AbstractTransactionRole { return this.self.linkedUser } - public getCrossGroupType(): CrossGroupType { - if (this.isCrossGroupTransaction()) { - return CrossGroupType.OUTBOUND - } - return CrossGroupType.LOCAL + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const signingUser = await this.loadUser(this.self.user) + const recipientUser = await this.loadUser(this.self.linkedUser) + return builder + .setTransactionTransfer( + new TransferAmount(new MemoryBlock(signingUser.derive2Pubkey), this.self.amount.toString()), + new MemoryBlock(recipientUser.derive2Pubkey), + ) + .setMemo('dummy memo for transfer') } } diff --git a/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts index 23fd9d275..e8730f8e3 100644 --- a/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts +++ b/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts @@ -1,68 +1,78 @@ +/* eslint-disable camelcase */ import { Transaction } from '@entity/Transaction' +import { + GradidoTransaction, + GradidoTransactionBuilder, + InteractionSerialize, + InteractionValidate, + MemoryBlock, + TransactionType_COMMUNITY_ROOT, + ValidateType_SINGLE, +} from 'gradido-blockchain-js' import { sendMessage as iotaSendMessage } from '@/client/IotaClient' -import { KeyPair } from '@/data/KeyPair' -import { GradidoTransaction } from '@/data/proto/3_3/GradidoTransaction' -import { SignaturePair } from '@/data/proto/3_3/SignaturePair' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionError } from '@/graphql/model/TransactionError' -import { GradidoTransactionLoggingView } from '@/logging/GradidoTransactionLogging.view' import { logger } from '@/logging/logger' export abstract class AbstractTransactionRecipeRole { - protected transactionBody: TransactionBody - public constructor(protected self: Transaction) { - this.transactionBody = TransactionBody.fromBodyBytes(this.self.bodyBytes) - } + // eslint-disable-next-line no-useless-constructor + public constructor(protected self: Transaction) {} public abstract transmitToIota(): Promise + public abstract getCrossGroupTypeName(): string - protected getGradidoTransaction(): GradidoTransaction { - const transaction = new GradidoTransaction(this.transactionBody) + public validate(transactionBuilder: GradidoTransactionBuilder): GradidoTransaction { + const transaction = transactionBuilder.build() + try { + // throw an exception when something is wrong + const validator = new InteractionValidate(transaction) + validator.run(ValidateType_SINGLE) + } catch (e) { + if (e instanceof Error) { + throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e.message) + } else if (typeof e === 'string') { + throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e) + } else { + throw e + } + } + return transaction + } + + protected getGradidoTransactionBuilder(): GradidoTransactionBuilder { if (!this.self.signature) { throw new TransactionError( TransactionErrorType.MISSING_PARAMETER, 'missing signature in transaction recipe', ) } - const signaturePair = new SignaturePair() - if (this.self.signature.length !== 64) { - throw new TransactionError(TransactionErrorType.INVALID_SIGNATURE, "signature isn't 64 bytes") - } - signaturePair.signature = this.self.signature - if (this.transactionBody.communityRoot) { - const publicKey = this.self.community.rootPubkey + let publicKey: Buffer | undefined + if (this.self.type === TransactionType_COMMUNITY_ROOT) { + publicKey = this.self.community.rootPubkey if (!publicKey) { throw new TransactionError( TransactionErrorType.MISSING_PARAMETER, 'missing community public key for community root transaction', ) } - signaturePair.pubKey = publicKey } else if (this.self.signingAccount) { - const publicKey = this.self.signingAccount.derive2Pubkey + publicKey = this.self.signingAccount.derive2Pubkey if (!publicKey) { throw new TransactionError( TransactionErrorType.MISSING_PARAMETER, 'missing signing account public key for transaction', ) } - signaturePair.pubKey = publicKey } else { throw new TransactionError( TransactionErrorType.NOT_FOUND, "signingAccount not exist and it isn't a community root transaction", ) } - if (signaturePair.validate()) { - transaction.sigMap.sigPair.push(signaturePair) - } - if (!KeyPair.verify(transaction.bodyBytes, signaturePair)) { - logger.debug('invalid signature', new GradidoTransactionLoggingView(transaction)) - throw new TransactionError(TransactionErrorType.INVALID_SIGNATURE, 'signature is invalid') - } - return transaction + return new GradidoTransactionBuilder() + .setTransactionBody(new MemoryBlock(this.self.bodyBytes)) + .addSignaturePair(new MemoryBlock(publicKey), new MemoryBlock(this.self.signature)) } /** @@ -76,9 +86,15 @@ export abstract class AbstractTransactionRecipeRole { topic: string, ): Promise { // protobuf serializing function - const messageBuffer = GradidoTransaction.encode(gradidoTransaction).finish() + const serialized = new InteractionSerialize(gradidoTransaction).run() + if (!serialized) { + throw new TransactionError( + TransactionErrorType.PROTO_ENCODE_ERROR, + 'cannot serialize transaction', + ) + } const resultMessage = await iotaSendMessage( - messageBuffer, + Uint8Array.from(serialized.data()), Uint8Array.from(Buffer.from(topic, 'hex')), ) logger.info('transmitted Gradido Transaction to Iota', { diff --git a/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts index 2f18b48ac..afa171a37 100644 --- a/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts +++ b/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts @@ -1,6 +1,6 @@ import { Transaction } from '@entity/Transaction' +import { MemoryBlock } from 'gradido-blockchain-js' -import { TransactionLogic } from '@/data/Transaction.logic' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { LogError } from '@/server/LogError' @@ -12,9 +12,13 @@ import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role' * need to set gradido id from OUTBOUND transaction! */ export class InboundTransactionRecipeRole extends AbstractTransactionRecipeRole { + public getCrossGroupTypeName(): string { + return 'INBOUND' + } + public async transmitToIota(): Promise { logger.debug('transmit INBOUND transaction to iota', new TransactionLoggingView(this.self)) - const gradidoTransaction = this.getGradidoTransaction() + const builder = this.getGradidoTransactionBuilder() const pairingTransaction = await new TransactionLogic(this.self).findPairTransaction() if (!pairingTransaction.iotaMessageId || pairingTransaction.iotaMessageId.length !== 32) { throw new LogError( @@ -22,7 +26,7 @@ export class InboundTransactionRecipeRole extends AbstractTransactionRecipeRole new TransactionLoggingView(pairingTransaction), ) } - gradidoTransaction.parentMessageId = pairingTransaction.iotaMessageId + builder.setParentMessageId(new MemoryBlock(pairingTransaction.iotaMessageId)) this.self.pairingTransactionId = pairingTransaction.id this.self.pairingTransaction = pairingTransaction pairingTransaction.pairingTransactionId = this.self.id @@ -32,7 +36,7 @@ export class InboundTransactionRecipeRole extends AbstractTransactionRecipeRole } this.self.iotaMessageId = await this.sendViaIota( - gradidoTransaction, + this.validate(builder), this.self.otherCommunity.iotaTopic, ) return this.self diff --git a/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts index 60cc58ff7..10f862d9a 100644 --- a/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts +++ b/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts @@ -1,23 +1,22 @@ import { Transaction } from '@entity/Transaction' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role' export class LocalTransactionRecipeRole extends AbstractTransactionRecipeRole { + public getCrossGroupTypeName(): string { + return 'LOCAL' + } + public async transmitToIota(): Promise { - let transactionCrossGroupTypeName = 'LOCAL' - if (this.transactionBody) { - transactionCrossGroupTypeName = CrossGroupType[this.transactionBody.type] - } logger.debug( - `transmit ${transactionCrossGroupTypeName} transaction to iota`, + `transmit ${this.getCrossGroupTypeName()} transaction to iota`, new TransactionLoggingView(this.self), ) this.self.iotaMessageId = await this.sendViaIota( - this.getGradidoTransaction(), + this.validate(this.getGradidoTransactionBuilder()), this.self.community.iotaTopic, ) return this.self diff --git a/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts b/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts index a54cd8ec3..d3b0b67c4 100644 --- a/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts +++ b/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts @@ -3,4 +3,8 @@ import { LocalTransactionRecipeRole } from './LocalTransactionRecipe.role' /** * Outbound Transaction on sender community, mark the gradidos as sended out of community */ -export class OutboundTransactionRecipeRole extends LocalTransactionRecipeRole {} +export class OutboundTransactionRecipeRole extends LocalTransactionRecipeRole { + public getCrossGroupTypeName(): string { + return 'OUTBOUND' + } +} diff --git a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts index 520c4e143..f366be2b4 100644 --- a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts +++ b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts @@ -1,6 +1,7 @@ import 'reflect-metadata' import { Account } from '@entity/Account' import { Decimal } from 'decimal.js-light' +import { CrossGroupType_INBOUND, CrossGroupType_OUTBOUND, InteractionDeserialize, InteractionToJson, InteractionValidate, MemoryBlock } from 'gradido-blockchain-js' import { v4 } from 'uuid' import { TestDB } from '@test/TestDB' @@ -8,8 +9,6 @@ import { TestDB } from '@test/TestDB' import { CONFIG } from '@/config' import { KeyPair } from '@/data/KeyPair' import { Mnemonic } from '@/data/Mnemonic' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { logger } from '@/logging/logger' @@ -76,7 +75,7 @@ describe('interactions/transmitToIota/TransmitToIotaContext', () => { it('LOCAL transaction', async () => { const creationTransactionDraft = new TransactionDraft() - creationTransactionDraft.amount = new Decimal('2000') + creationTransactionDraft.amount = new Decimal('1000') creationTransactionDraft.backendTransactionId = 1 creationTransactionDraft.createdAt = new Date().toISOString() creationTransactionDraft.linkedUser = moderator.identifier @@ -116,8 +115,11 @@ describe('interactions/transmitToIota/TransmitToIotaContext', () => { await transactionRecipeContext.run() const transaction = transactionRecipeContext.getTransactionRecipe() await transaction.save() - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) - expect(body.type).toBe(CrossGroupType.OUTBOUND) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body).not.toBeNull() + expect(body?.getType()).toEqual(CrossGroupType_OUTBOUND) const context = new TransmitToIotaContext(transaction) const debugSpy = jest.spyOn(logger, 'debug') await context.run() @@ -148,8 +150,10 @@ describe('interactions/transmitToIota/TransmitToIotaContext', () => { const transaction = transactionRecipeContext.getTransactionRecipe() await transaction.save() // console.log(new TransactionLoggingView(transaction)) - const body = TransactionBody.fromBodyBytes(transaction.bodyBytes) - expect(body.type).toBe(CrossGroupType.INBOUND) + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const body = deserializer.getTransactionBody() + expect(body?.getType()).toEqual(CrossGroupType_INBOUND) const context = new TransmitToIotaContext(transaction) const debugSpy = jest.spyOn(logger, 'debug') diff --git a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts index e58cd7e89..69c9ade3f 100644 --- a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts +++ b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts @@ -1,7 +1,15 @@ +/* eslint-disable camelcase */ import { Transaction } from '@entity/Transaction' +import { + CrossGroupType_INBOUND, + CrossGroupType_LOCAL, + CrossGroupType_OUTBOUND, + InteractionDeserialize, + MemoryBlock, +} from 'gradido-blockchain-js' -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionError } from '@/graphql/model/TransactionError' import { logger } from '@/logging/logger' import { TransactionLoggingView } from '@/logging/TransactionLogging.view' import { LogError } from '@/server/LogError' @@ -21,19 +29,27 @@ export class TransmitToIotaContext { private transactionRecipeRole: AbstractTransactionRecipeRole public constructor(transaction: Transaction) { - const transactionBody = TransactionBody.fromBodyBytes(transaction.bodyBytes) - switch (transactionBody.type) { - case CrossGroupType.LOCAL: + const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) + deserializer.run() + const transactionBody = deserializer.getTransactionBody() + if (!transactionBody) { + throw new TransactionError( + TransactionErrorType.PROTO_DECODE_ERROR, + 'error decoding body bytes', + ) + } + switch (transactionBody.getType()) { + case CrossGroupType_LOCAL: this.transactionRecipeRole = new LocalTransactionRecipeRole(transaction) break - case CrossGroupType.INBOUND: + case CrossGroupType_INBOUND: this.transactionRecipeRole = new InboundTransactionRecipeRole(transaction) break - case CrossGroupType.OUTBOUND: + case CrossGroupType_OUTBOUND: this.transactionRecipeRole = new OutboundTransactionRecipeRole(transaction) break default: - throw new LogError('unknown cross group type', transactionBody.type) + throw new LogError('unknown cross group type', transactionBody.getType()) } } diff --git a/dlt-connector/src/logging/AbstractLogging.view.ts b/dlt-connector/src/logging/AbstractLogging.view.ts index ad52e6530..e5f439b5d 100644 --- a/dlt-connector/src/logging/AbstractLogging.view.ts +++ b/dlt-connector/src/logging/AbstractLogging.view.ts @@ -1,10 +1,7 @@ import util from 'util' import { Decimal } from 'decimal.js-light' - -import { Timestamp } from '@/data/proto/3_3/Timestamp' -import { TimestampSeconds } from '@/data/proto/3_3/TimestampSeconds' -import { timestampSecondsToDate, timestampToDate } from '@/utils/typeConverter' +import { Timestamp, TimestampSeconds } from 'gradido-blockchain-js' export abstract class AbstractLoggingView { protected bufferStringFormat: BufferEncoding = 'hex' @@ -36,14 +33,14 @@ export abstract class AbstractLoggingView { } protected timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { - if (timestamp && timestamp.seconds) { - return timestampSecondsToDate(timestamp).toISOString() + if (timestamp && timestamp.getSeconds()) { + return timestamp.getDate().toISOString() } } protected timestampToDateString(timestamp: Timestamp): string | undefined { - if (timestamp && (timestamp.seconds || timestamp.nanoSeconds)) { - return timestampToDate(timestamp).toISOString() + if (timestamp && (timestamp.getSeconds() || timestamp.getNanos())) { + return timestamp.getDate().toISOString() } } } diff --git a/dlt-connector/src/logging/AccountLogging.view.ts b/dlt-connector/src/logging/AccountLogging.view.ts index 0c97ce469..f1a7abe20 100644 --- a/dlt-connector/src/logging/AccountLogging.view.ts +++ b/dlt-connector/src/logging/AccountLogging.view.ts @@ -1,7 +1,8 @@ import { Account } from '@entity/Account' +import { addressTypeToString } from 'gradido-blockchain-js' -import { AddressType } from '@/data/proto/3_3/enum/AddressType' -import { getEnumValue } from '@/utils/typeConverter' +import { AccountType } from '@/graphql/enum/AccountType' +import { accountTypeToAddressType } from '@/utils/typeConverter' import { AbstractLoggingView } from './AbstractLogging.view' import { UserLoggingView } from './UserLogging.view' @@ -17,7 +18,9 @@ export class AccountLoggingView extends AbstractLoggingView { user: this.account.user ? new UserLoggingView(this.account.user).toJSON() : null, derivationIndex: this.account.derivationIndex, derive2Pubkey: this.account.derive2Pubkey.toString(this.bufferStringFormat), - type: getEnumValue(AddressType, this.account.type), + type: addressTypeToString( + accountTypeToAddressType(this.account.type as unknown as AccountType), + ), createdAt: this.dateToString(this.account.createdAt), confirmedAt: this.dateToString(this.account.confirmedAt), balanceOnConfirmation: this.decimalToString(this.account.balanceOnConfirmation), diff --git a/dlt-connector/src/logging/CommunityRootLogging.view.ts b/dlt-connector/src/logging/CommunityRootLogging.view.ts deleted file mode 100644 index ba2869755..000000000 --- a/dlt-connector/src/logging/CommunityRootLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { CommunityRoot } from '@/data/proto/3_3/CommunityRoot' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class CommunityRootLoggingView extends AbstractLoggingView { - public constructor(private self: CommunityRoot) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - rootPubkey: Buffer.from(this.self.rootPubkey).toString(this.bufferStringFormat), - gmwPubkey: Buffer.from(this.self.gmwPubkey).toString(this.bufferStringFormat), - aufPubkey: Buffer.from(this.self.aufPubkey).toString(this.bufferStringFormat), - } - } -} diff --git a/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts b/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts deleted file mode 100644 index 8e894a35a..000000000 --- a/dlt-connector/src/logging/ConfirmedTransactionLogging.view.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ConfirmedTransaction } from '@/data/proto/3_3/ConfirmedTransaction' -import { timestampSecondsToDate } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { GradidoTransactionLoggingView } from './GradidoTransactionLogging.view' - -export class ConfirmedTransactionLoggingView extends AbstractLoggingView { - public constructor(private self: ConfirmedTransaction) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - id: this.self.id.toString(), - transaction: new GradidoTransactionLoggingView(this.self.transaction).toJSON(), - confirmedAt: this.dateToString(timestampSecondsToDate(this.self.confirmedAt)), - versionNumber: this.self.versionNumber, - runningHash: Buffer.from(this.self.runningHash).toString(this.bufferStringFormat), - messageId: Buffer.from(this.self.messageId).toString(this.bufferStringFormat), - accountBalance: this.self.accountBalance, - } - } -} diff --git a/dlt-connector/src/logging/GradidoCreationLogging.view.ts b/dlt-connector/src/logging/GradidoCreationLogging.view.ts deleted file mode 100644 index 43e14b887..000000000 --- a/dlt-connector/src/logging/GradidoCreationLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { GradidoCreation } from '@/data/proto/3_3/GradidoCreation' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { TransferAmountLoggingView } from './TransferAmountLogging.view' - -export class GradidoCreationLoggingView extends AbstractLoggingView { - public constructor(private self: GradidoCreation) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - recipient: new TransferAmountLoggingView(this.self.recipient).toJSON(), - targetDate: this.timestampSecondsToDateString(this.self.targetDate), - } - } -} diff --git a/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts b/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts deleted file mode 100644 index 89a1f1a29..000000000 --- a/dlt-connector/src/logging/GradidoDeferredTransferLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { GradidoDeferredTransfer } from '@/data/proto/3_3/GradidoDeferredTransfer' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { GradidoTransferLoggingView } from './GradidoTransferLogging.view' - -export class GradidoDeferredTransferLoggingView extends AbstractLoggingView { - public constructor(private self: GradidoDeferredTransfer) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - ...new GradidoTransferLoggingView(this.self.transfer).toJSON(), - ...{ timeout: this.timestampSecondsToDateString(this.self.timeout) }, - } - } -} diff --git a/dlt-connector/src/logging/GradidoTransactionLogging.view.ts b/dlt-connector/src/logging/GradidoTransactionLogging.view.ts deleted file mode 100644 index f23c0b05e..000000000 --- a/dlt-connector/src/logging/GradidoTransactionLogging.view.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { GradidoTransaction } from '@/data/proto/3_3/GradidoTransaction' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { SignatureMapLoggingView } from './SignatureMapLogging.view' -import { TransactionBodyLoggingView } from './TransactionBodyLogging.view' - -export class GradidoTransactionLoggingView extends AbstractLoggingView { - public constructor(private self: GradidoTransaction) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - let transactionBody: TransactionBody | null | unknown = null - try { - transactionBody = new TransactionBodyLoggingView(this.self.getTransactionBody()) - } catch (e) { - transactionBody = e - } - return { - sigMap: new SignatureMapLoggingView(this.self.sigMap).toJSON(), - bodyBytes: transactionBody, - parentMessageId: this.self.parentMessageId - ? Buffer.from(this.self.parentMessageId).toString(this.bufferStringFormat) - : undefined, - } - } -} diff --git a/dlt-connector/src/logging/GradidoTransferLogging.view.ts b/dlt-connector/src/logging/GradidoTransferLogging.view.ts deleted file mode 100644 index 84b5fe604..000000000 --- a/dlt-connector/src/logging/GradidoTransferLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { GradidoTransfer } from '@/data/proto/3_3/GradidoTransfer' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { TransferAmountLoggingView } from './TransferAmountLogging.view' - -export class GradidoTransferLoggingView extends AbstractLoggingView { - public constructor(private self: GradidoTransfer) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - sender: new TransferAmountLoggingView(this.self.sender), - recipient: Buffer.from(this.self.recipient).toString(this.bufferStringFormat), - } - } -} diff --git a/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts b/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts deleted file mode 100644 index 8d1159d82..000000000 --- a/dlt-connector/src/logging/GroupFriendsUpdateLogging.view.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { GroupFriendsUpdate } from '@/data/proto/3_3/GroupFriendsUpdate' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class GroupFriendsUpdateLoggingView extends AbstractLoggingView { - public constructor(private self: GroupFriendsUpdate) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - colorFusion: this.self.colorFusion, - } - } -} diff --git a/dlt-connector/src/logging/RegisterAddressLogging.view.ts b/dlt-connector/src/logging/RegisterAddressLogging.view.ts deleted file mode 100644 index bb857e2b8..000000000 --- a/dlt-connector/src/logging/RegisterAddressLogging.view.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { AddressType } from '@/data/proto/3_3/enum/AddressType' -import { RegisterAddress } from '@/data/proto/3_3/RegisterAddress' -import { getEnumValue } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class RegisterAddressLoggingView extends AbstractLoggingView { - public constructor(private self: RegisterAddress) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - userPublicKey: Buffer.from(this.self.userPubkey).toString(this.bufferStringFormat), - addressType: getEnumValue(AddressType, this.self.addressType), - nameHash: Buffer.from(this.self.nameHash).toString(this.bufferStringFormat), - accountPublicKey: Buffer.from(this.self.accountPubkey).toString(this.bufferStringFormat), - derivationIndex: this.self.derivationIndex, - } - } -} diff --git a/dlt-connector/src/logging/SignatureMapLogging.view.ts b/dlt-connector/src/logging/SignatureMapLogging.view.ts deleted file mode 100644 index 93feb46f9..000000000 --- a/dlt-connector/src/logging/SignatureMapLogging.view.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SignatureMap } from '@/data/proto/3_3/SignatureMap' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { SignaturePairLoggingView } from './SignaturePairLogging.view' - -export class SignatureMapLoggingView extends AbstractLoggingView { - public constructor(private self: SignatureMap) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - sigPair: this.self.sigPair.map((value) => new SignaturePairLoggingView(value).toJSON()), - } - } -} diff --git a/dlt-connector/src/logging/SignaturePairLogging.view.ts b/dlt-connector/src/logging/SignaturePairLogging.view.ts deleted file mode 100644 index e88406098..000000000 --- a/dlt-connector/src/logging/SignaturePairLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { SignaturePair } from '@/data/proto/3_3/SignaturePair' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class SignaturePairLoggingView extends AbstractLoggingView { - public constructor(private self: SignaturePair) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - pubkey: Buffer.from(this.self.pubKey).toString(this.bufferStringFormat), - signature: - Buffer.from(this.self.signature).subarray(0, 31).toString(this.bufferStringFormat) + '..', - } - } -} diff --git a/dlt-connector/src/logging/TransactionBodyLogging.view.ts b/dlt-connector/src/logging/TransactionBodyLogging.view.ts deleted file mode 100644 index 0c287b0a5..000000000 --- a/dlt-connector/src/logging/TransactionBodyLogging.view.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' -import { getEnumValue } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { CommunityRootLoggingView } from './CommunityRootLogging.view' -import { GradidoCreationLoggingView } from './GradidoCreationLogging.view' -import { GradidoDeferredTransferLoggingView } from './GradidoDeferredTransferLogging.view' -import { GradidoTransferLoggingView } from './GradidoTransferLogging.view' -import { GroupFriendsUpdateLoggingView } from './GroupFriendsUpdateLogging.view' -import { RegisterAddressLoggingView } from './RegisterAddressLogging.view' - -export class TransactionBodyLoggingView extends AbstractLoggingView { - public constructor(private self: TransactionBody) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - memo: this.self.memo, - createdAt: this.timestampToDateString(this.self.createdAt), - versionNumber: this.self.versionNumber, - type: getEnumValue(CrossGroupType, this.self.type), - otherGroup: this.self.otherGroup, - transfer: this.self.transfer - ? new GradidoTransferLoggingView(this.self.transfer).toJSON() - : undefined, - creation: this.self.creation - ? new GradidoCreationLoggingView(this.self.creation).toJSON() - : undefined, - groupFriendsUpdate: this.self.groupFriendsUpdate - ? new GroupFriendsUpdateLoggingView(this.self.groupFriendsUpdate).toJSON() - : undefined, - registerAddress: this.self.registerAddress - ? new RegisterAddressLoggingView(this.self.registerAddress).toJSON() - : undefined, - deferredTransfer: this.self.deferredTransfer - ? new GradidoDeferredTransferLoggingView(this.self.deferredTransfer).toJSON() - : undefined, - communityRoot: this.self.communityRoot - ? new CommunityRootLoggingView(this.self.communityRoot).toJSON() - : undefined, - } - } -} diff --git a/dlt-connector/src/logging/TransferAmountLogging.view.ts b/dlt-connector/src/logging/TransferAmountLogging.view.ts deleted file mode 100644 index 2384bfdb4..000000000 --- a/dlt-connector/src/logging/TransferAmountLogging.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { TransferAmount } from '@/data/proto/3_3/TransferAmount' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class TransferAmountLoggingView extends AbstractLoggingView { - public constructor(private self: TransferAmount) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - pubkey: Buffer.from(this.self.pubkey).toString(this.bufferStringFormat), - amount: this.self.amount, - communityId: this.self.communityId, - } - } -} diff --git a/dlt-connector/src/utils/derivationHelper.test.ts b/dlt-connector/src/utils/derivationHelper.test.ts index f14b99cdf..6d3d690ee 100644 --- a/dlt-connector/src/utils/derivationHelper.test.ts +++ b/dlt-connector/src/utils/derivationHelper.test.ts @@ -1,16 +1,10 @@ import 'reflect-metadata' -import { Timestamp } from '../data/proto/3_3/Timestamp' import { hardenDerivationIndex, HARDENED_KEY_BITMASK } from './derivationHelper' -import { timestampToDate } from './typeConverter' describe('utils', () => { it('test bitmask for hardened keys', () => { const derivationIndex = hardenDerivationIndex(1) expect(derivationIndex).toBeGreaterThan(HARDENED_KEY_BITMASK) }) - it('test TimestampToDate', () => { - const date = new Date('2011-04-17T12:01:10.109') - expect(timestampToDate(new Timestamp(date))).toEqual(date) - }) }) diff --git a/dlt-connector/src/utils/typeConverter.test.ts b/dlt-connector/src/utils/typeConverter.test.ts index 4caee94bb..05fb903b6 100644 --- a/dlt-connector/src/utils/typeConverter.test.ts +++ b/dlt-connector/src/utils/typeConverter.test.ts @@ -1,14 +1,6 @@ import 'reflect-metadata' -import { Timestamp } from '@/data/proto/3_3/Timestamp' - -import { - base64ToBuffer, - iotaTopicFromCommunityUUID, - timestampSecondsToDate, - timestampToDate, - uuid4ToBuffer, -} from './typeConverter' +import { base64ToBuffer, iotaTopicFromCommunityUUID, uuid4ToBuffer } from './typeConverter' describe('utils/typeConverter', () => { it('uuid4ToBuffer', () => { @@ -23,20 +15,6 @@ describe('utils/typeConverter', () => { ) }) - it('timestampToDate', () => { - const now = new Date('Thu, 05 Oct 2023 11:55:18.102 +0000') - const timestamp = new Timestamp(now) - expect(timestamp.seconds).toBe(Math.round(now.getTime() / 1000)) - expect(timestampToDate(timestamp)).toEqual(now) - }) - - it('timestampSecondsToDate', () => { - const now = new Date('Thu, 05 Oct 2023 11:55:18.102 +0000') - const timestamp = new Timestamp(now) - expect(timestamp.seconds).toBe(Math.round(now.getTime() / 1000)) - expect(timestampSecondsToDate(timestamp)).toEqual(new Date('Thu, 05 Oct 2023 11:55:18 +0000')) - }) - it('base64ToBuffer', () => { expect(base64ToBuffer('MTizWQMR/fCoI+FzyqlIe30nXCP6sHEGtLE2TLA4r/0=')).toStrictEqual( Buffer.from('3138b3590311fdf0a823e173caa9487b7d275c23fab07106b4b1364cb038affd', 'hex'), diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 52dcd2a98..9290fdd82 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -1,14 +1,17 @@ +/* eslint-disable camelcase */ +import { + AddressType, + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, + AddressType_COMMUNITY_HUMAN, + AddressType_COMMUNITY_PROJECT, + AddressType_CRYPTO_ACCOUNT, + AddressType_NONE, + AddressType_SUBACCOUNT, +} from 'gradido-blockchain-js' import { crypto_generichash as cryptoHash } from 'sodium-native' -import { AddressType } from '@/data/proto/3_3/enum/AddressType' -import { Timestamp } from '@/data/proto/3_3/Timestamp' -import { TimestampSeconds } from '@/data/proto/3_3/TimestampSeconds' -import { TransactionBody } from '@/data/proto/3_3/TransactionBody' import { AccountType } from '@/graphql/enum/AccountType' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' export const uuid4ToBuffer = (uuid: string): Buffer => { // Remove dashes from the UUIDv4 string @@ -26,44 +29,10 @@ export const iotaTopicFromCommunityUUID = (communityUUID: string): string => { return hash.toString('hex') } -export const timestampToDate = (timestamp: Timestamp): Date => { - let milliseconds = timestamp.nanoSeconds / 1000000 - milliseconds += timestamp.seconds * 1000 - return new Date(milliseconds) -} - -export const timestampSecondsToDate = (timestamp: TimestampSeconds): Date => { - return new Date(timestamp.seconds * 1000) -} - export const base64ToBuffer = (base64: string): Buffer => { return Buffer.from(base64, 'base64') } -export const bodyBytesToTransactionBody = (bodyBytes: Buffer): TransactionBody => { - try { - return TransactionBody.decode(new Uint8Array(bodyBytes)) - } catch (error) { - logger.error('error decoding body from gradido transaction: %s', error) - throw new TransactionError( - TransactionErrorType.PROTO_DECODE_ERROR, - 'cannot decode body from gradido transaction', - ) - } -} - -export const transactionBodyToBodyBytes = (transactionBody: TransactionBody): Buffer => { - try { - return Buffer.from(TransactionBody.encode(transactionBody).finish()) - } catch (error) { - logger.error('error encoding transaction body to body bytes', error) - throw new TransactionError( - TransactionErrorType.PROTO_ENCODE_ERROR, - 'cannot encode transaction body', - ) - } -} - export function getEnumValue>( enumType: T, value: number | string, @@ -81,27 +50,39 @@ export function getEnumValue>( } export const accountTypeToAddressType = (type: AccountType): AddressType => { - const typeString: string = AccountType[type] - const addressType: AddressType = AddressType[typeString as keyof typeof AddressType] - - if (!addressType) { - throw new LogError("couldn't find corresponding AddressType for AccountType", { - accountType: type, - addressTypes: Object.keys(AddressType), - }) + switch (type) { + case AccountType.COMMUNITY_AUF: + return AddressType_COMMUNITY_AUF + case AccountType.COMMUNITY_GMW: + return AddressType_COMMUNITY_GMW + case AccountType.COMMUNITY_HUMAN: + return AddressType_COMMUNITY_HUMAN + case AccountType.COMMUNITY_PROJECT: + return AddressType_COMMUNITY_PROJECT + case AccountType.CRYPTO_ACCOUNT: + return AddressType_CRYPTO_ACCOUNT + case AccountType.SUBACCOUNT: + return AddressType_SUBACCOUNT + default: + return AddressType_NONE } - return addressType } export const addressTypeToAccountType = (type: AddressType): AccountType => { - const typeString: string = AddressType[type] - const accountType: AccountType = AccountType[typeString as keyof typeof AccountType] - - if (!accountType) { - throw new LogError("couldn't find corresponding AccountType for AddressType", { - addressTypes: type, - accountType: Object.keys(AccountType), - }) + switch (type) { + case AddressType_COMMUNITY_AUF: + return AccountType.COMMUNITY_AUF + case AddressType_COMMUNITY_GMW: + return AccountType.COMMUNITY_GMW + case AddressType_COMMUNITY_HUMAN: + return AccountType.COMMUNITY_HUMAN + case AddressType_COMMUNITY_PROJECT: + return AccountType.COMMUNITY_PROJECT + case AddressType_CRYPTO_ACCOUNT: + return AccountType.CRYPTO_ACCOUNT + case AddressType_SUBACCOUNT: + return AccountType.SUBACCOUNT + default: + return AccountType.NONE } - return accountType } diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index 3188c39a0..33c00a820 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -2,18 +2,13 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@apollo/cache-control-types@^1.0.3": version "1.0.3" @@ -49,9 +44,9 @@ "@apollo/utils.logger" "^2.0.0" "@apollo/server@^4.7.5": - version "4.9.3" - resolved "https://registry.yarnpkg.com/@apollo/server/-/server-4.9.3.tgz#d51fa1745a7e9f3b1d687c6df40256744aaa977a" - integrity sha512-U56Sx/UmzR3Es344hQ/Ptf2EJrH+kV4ZPoLmgGjWoiwf2wYQ/pRSvkSXgjOvoyE34wSa8Gh7f92ljfLfY+6q1w== + version "4.11.0" + resolved "https://registry.yarnpkg.com/@apollo/server/-/server-4.11.0.tgz#21c0f10ad805192a5485e58ed5c5b3dbe2243174" + integrity sha512-SWDvbbs0wl2zYhKG6aGLxwTJ72xpqp0awb2lotNpfezd9VcAvzaUizzKQqocephin2uMoaA8MguoyBmgtPzNWw== dependencies: "@apollo/cache-control-types" "^1.0.3" "@apollo/server-gateway-interface" "^1.1.1" @@ -64,12 +59,10 @@ "@apollo/utils.usagereporting" "^2.1.0" "@apollo/utils.withrequired" "^2.0.0" "@graphql-tools/schema" "^9.0.0" - "@josephg/resolvable" "^1.0.0" "@types/express" "^4.17.13" "@types/express-serve-static-core" "^4.17.30" "@types/node-fetch" "^2.6.1" async-retry "^1.2.1" - body-parser "^1.20.0" cors "^2.8.5" express "^4.17.1" loglevel "^1.6.8" @@ -106,9 +99,9 @@ integrity sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A== "@apollo/utils.fetcher@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@apollo/utils.fetcher/-/utils.fetcher-3.0.0.tgz#1eb49f95a09fc7e34f9e000af29ff5ec05f808bf" - integrity sha512-WL4pabs5TwWyl2ho0DMk5uRtsD4ORsP/7po83y03CrkCCBAB+E4cs6OteLPaQtizYGiBfMpANxWi11Cy3pwsUA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.fetcher/-/utils.fetcher-3.1.0.tgz#0639c30a5ac57e3e62784b180495023f5e886fe0" + integrity sha512-Z3QAyrsQkvrdTuHAFwWDNd+0l50guwoQUoaDQssLOjkmnmVuvXlJykqlEJolio+4rFwBnWdoY1ByFdKaQEcm7A== "@apollo/utils.isnodelike@^2.0.0", "@apollo/utils.isnodelike@^2.0.1": version "2.0.1" @@ -167,155 +160,131 @@ resolved "https://registry.yarnpkg.com/@apollo/utils.withrequired/-/utils.withrequired-2.0.1.tgz#e72bc512582a6f26af150439f7eb7473b46ba874" integrity sha512-YBDiuAX9i1lLc6GeTy1m7DGLFn/gMnvXqlalOIMjM7DeOgIacEjjfwPqb0M1CQ2v11HhR15d1NmxJoRCfrNqcA== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" -"@babel/compat-data@^7.22.9": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" - integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" - integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.23.0" - "@babel/helpers" "^7.23.0" - "@babel/parser" "^7.23.0" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.0" - "@babel/types" "^7.23.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.23.0", "@babel/generator@^7.7.2": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" - integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== +"@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== dependencies: - "@babel/types" "^7.23.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.25.6" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" - integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.15" - browserslist "^4.21.9" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== +"@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== dependencies: - "@babel/types" "^7.22.5" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" -"@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== dependencies: - "@babel/types" "^7.22.15" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" -"@babel/helper-module-transforms@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" - integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" - integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" - integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== - -"@babel/helpers@^7.23.0": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" - integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== - dependencies: - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.0" - "@babel/types" "^7.23.0" - -"@babel/highlight@^7.22.13": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" - integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-validator-identifier" "^7.24.7" chalk "^2.4.2" js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" - integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -331,14 +300,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz#6d4c78f042db0e82fd6436cd65fec5dc78ad2bde" + integrity sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -352,7 +335,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -366,7 +349,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -394,7 +377,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -402,51 +392,41 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" - integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" + integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.8" -"@babel/runtime@^7.21.0": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" - integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== +"@babel/template@^7.25.0", "@babel/template@^7.3.3": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== dependencies: - regenerator-runtime "^0.14.0" + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" -"@babel/template@^7.22.15", "@babel/template@^7.3.3": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== +"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2", "@babel/traverse@^7.7.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.23.0", "@babel/traverse@^7.7.2": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" - integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.23.0" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.0" - "@babel/types" "^7.23.0" - debug "^4.1.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.6" + "@babel/parser" "^7.25.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" + debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.3.3": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" - integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -477,14 +457,14 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162" - integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ== + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -496,15 +476,15 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.50.0": - version "8.50.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" - integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@faker-js/faker@^8.0.2": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.1.0.tgz#e14896f1c57af2495e341dc4c7bf04125c8aeafd" - integrity sha512-38DT60rumHfBYynif3lmtxMqMqmsOQIxQgEuPZxCk2yUYN0eqWpTACgxi0VpidvsJB8CRxCpvP7B3anK85FjtQ== +"@faker-js/faker@^8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451" + integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg== "@graphql-tools/merge@^8.4.1": version "8.4.2" @@ -514,31 +494,31 @@ "@graphql-tools/utils" "^9.2.1" tslib "^2.4.0" -"@graphql-tools/merge@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.0.0.tgz#b0a3636c82716454bff88e9bb40108b0471db281" - integrity sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q== +"@graphql-tools/merge@^9.0.6": + version "9.0.7" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.0.7.tgz#e37dd9491e65c00fb124f47073121d32dc6735d1" + integrity sha512-lbTrIuXIbUSmSumHkPRY1QX0Z8JEtmRhnIrkH7vkfeEmf0kNn/nCWvJwqokm5U7L+a+DA1wlRM4slIlbfXjJBA== dependencies: - "@graphql-tools/utils" "^10.0.0" + "@graphql-tools/utils" "^10.5.4" tslib "^2.4.0" "@graphql-tools/mock@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-9.0.0.tgz#9d4cd3d41333b2c09fee4f248a236aa959906b82" - integrity sha512-Vbb4RNTT9T3fXjmzACcflOh79vKBaC/J21eCJ0eug1ZdaM2QXVHQ3lxE6HNOlAENHXjwJINz1AnKsvF3bpeSKA== + version "9.0.4" + resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-9.0.4.tgz#6eb52a3f63646ea359ece60916b67c2cbc4fb9d4" + integrity sha512-/pfrBoL6QkKBrJcaOZ/2FtfoAYmiQE+L6Up3hWbSWjg1XJfecjqptLTcM2Wf0dmHAFkjCK1k4QVNHMmGJ94IOA== dependencies: - "@graphql-tools/schema" "^10.0.0" - "@graphql-tools/utils" "^10.0.0" + "@graphql-tools/schema" "^10.0.4" + "@graphql-tools/utils" "^10.2.1" fast-json-stable-stringify "^2.1.0" tslib "^2.4.0" -"@graphql-tools/schema@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.0.tgz#7b5f6b6a59f51c927de8c9069bde4ebbfefc64b3" - integrity sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg== +"@graphql-tools/schema@^10.0.4": + version "10.0.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.6.tgz#48391195ea4557ef5b6f77950bcbf529dc5f4e7e" + integrity sha512-EIJgPRGzpvDFEjVp+RF1zNNYIC36BYuIeZ514jFoJnI6IdxyVyIRDLx/ykgMdaa1pKQerpfdqDnsF4JnZoDHSQ== dependencies: - "@graphql-tools/merge" "^9.0.0" - "@graphql-tools/utils" "^10.0.0" + "@graphql-tools/merge" "^9.0.6" + "@graphql-tools/utils" "^10.5.4" tslib "^2.4.0" value-or-promise "^1.0.12" @@ -552,12 +532,13 @@ tslib "^2.4.0" value-or-promise "^1.0.12" -"@graphql-tools/utils@^10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.0.6.tgz#8a809d6bc0df27ffe8964696f182af2383b5974b" - integrity sha512-hZMjl/BbX10iagovakgf3IiqArx8TPsotq5pwBld37uIX1JiZoSbgbCIFol7u55bh32o6cfDEiiJgfAD5fbeyQ== +"@graphql-tools/utils@^10.2.1", "@graphql-tools/utils@^10.5.4": + version "10.5.4" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.5.4.tgz#214d815632a774f2db56bcaf7cfbd615ef858078" + integrity sha512-XHnyCWSlg1ccsD8s0y6ugo5GZ5TpkTiFVNPSYms5G0s6Z/xTuSmiLBfeqgkfaCwLmLaQnRCmNDL2JRnqc2R5bQ== dependencies: "@graphql-typed-document-node/core" "^3.1.1" + cross-inspect "1.0.1" dset "^3.1.2" tslib "^2.4.0" @@ -574,13 +555,31 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@graphql-yoga/subscription@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@graphql-yoga/subscription/-/subscription-5.0.1.tgz#affe9b4bca4303300cc9492d30dfbe9f089fe0e8" + integrity sha512-1wCB1DfAnaLzS+IdoOzELGGnx1ODEg9nzQXFh4u2j02vAnne6d+v4A7HIH9EqzVdPLoAaMKXCZUUdKs+j3z1fg== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@graphql-yoga/typed-event-target" "^3.0.0" + "@repeaterjs/repeater" "^3.0.4" + "@whatwg-node/events" "^0.1.0" + tslib "^2.5.2" + +"@graphql-yoga/typed-event-target@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@graphql-yoga/typed-event-target/-/typed-event-target-3.0.0.tgz#57dc42e052d8294555d26ee61854d72a0236fee0" + integrity sha512-w+liuBySifrstuHbFrHoHAEyVnDFVib+073q8AeAJ/qqJfvFvAwUPLLtNohR/WDVRgSasfXtl3dcNuVJWN+rjg== + dependencies: + "@repeaterjs/repeater" "^3.0.4" + tslib "^2.5.2" + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -588,10 +587,10 @@ 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== +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@iota/client@^2.2.4": version "2.2.4" @@ -798,34 +797,29 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@josephg/resolvable@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" - integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: - "@jridgewell/set-array" "^1.0.1" + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -835,19 +829,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@noble/hashes@^1.2.0": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== - "@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" @@ -869,6 +858,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -927,6 +921,16 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@repeaterjs/repeater@^3.0.4": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@repeaterjs/repeater/-/repeater-3.0.6.tgz#be23df0143ceec3c69f8b6c2517971a5578fdaa2" + integrity sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + "@sinonjs/commons@^1.7.0": version "1.8.6" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" @@ -952,9 +956,9 @@ integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -972,9 +976,9 @@ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.2.tgz#215db4f4a35d710256579784a548907237728756" - integrity sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" @@ -983,53 +987,53 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.5" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.5.tgz#281f4764bcbbbc51fdded0f25aa587b4ce14da95" - integrity sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w== + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.2.tgz#843e9f1f47c957553b0c374481dc4772921d6a6b" - integrity sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ== + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.2.tgz#4ddf99d95cfdd946ff35d2b65c978d9c9bf2645d" - integrity sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" "@types/body-parser@*": - version "1.19.3" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.3.tgz#fb558014374f7d9e56c8f34bab2042a3a07d25cd" - integrity sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ== + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" "@types/node" "*" "@types/connect@*": - version "3.4.36" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" - integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/cors@^2.8.13": - version "2.8.14" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.14.tgz#94eeb1c95eda6a8ab54870a3bf88854512f43a92" - integrity sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ== + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== dependencies: "@types/node" "*" "@types/express-serve-static-core@^4.17.30", "@types/express-serve-static-core@^4.17.33": - version "4.17.37" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz#7e4b7b59da9142138a2aaa7621f5abedce8c7320" - integrity sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg== + version "4.19.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" + integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -1037,9 +1041,9 @@ "@types/send" "*" "@types/express@^4.17.13": - version "4.17.18" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.18.tgz#efabf5c4495c1880df1bdffee604b143b29c4a95" - integrity sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ== + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "^4.17.33" @@ -1047,33 +1051,33 @@ "@types/serve-static" "*" "@types/graceful-fs@^4.1.2": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.7.tgz#30443a2e64fd51113bc3e2ba0914d47109695e2a" - integrity sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw== + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" "@types/http-errors@*": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.2.tgz#a86e00bbde8950364f8e7846687259ffcd96e8c2" - integrity sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg== + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#412e0725ef41cde73bfa03e0e833eaff41e0fd63" - integrity sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz#edc8e421991a3b4df875036d381fc0a5a982f549" - integrity sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" @@ -1086,9 +1090,9 @@ pretty-format "^27.0.0" "@types/json-schema@^7.0.9": - version "7.0.13" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" - integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" @@ -1100,47 +1104,46 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/mime@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" - integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== - "@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== + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== "@types/mysql@^2.15.8": - version "2.15.21" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.21.tgz#7516cba7f9d077f980100c85fd500c8210bd5e45" - integrity sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg== + version "2.15.26" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" + integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== dependencies: "@types/node" "*" "@types/node-fetch@^2.6.1": - version "2.6.6" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.6.tgz#b72f3f4bc0c0afee1c0bc9cff68e041d01e3e779" - integrity sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw== + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== dependencies: "@types/node" "*" form-data "^4.0.0" -"@types/node@*", "@types/node@^20.4.9": - version "20.7.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.0.tgz#c03de4572f114a940bc2ca909a33ddb2b925e470" - integrity sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg== - -"@types/node@>=13.7.0": - version "20.8.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25" - integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ== +"@types/node@*": + version "22.5.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44" + integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== dependencies: - undici-types "~5.25.1" + undici-types "~6.19.2" "@types/node@^18.11.18": - version "18.18.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.0.tgz#bd19d5133a6e5e2d0152ec079ac27c120e7f1763" - integrity sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw== + version "18.19.50" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.50.tgz#8652b34ee7c0e7e2004b3f08192281808d41bf5a" + integrity sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg== + dependencies: + undici-types "~5.26.4" + +"@types/node@^20.14.0": + version "20.16.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.5.tgz#d43c7f973b32ffdf9aa7bd4f80e1072310fd7a53" + integrity sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA== + dependencies: + undici-types "~6.19.2" "@types/prettier@^2.1.5": version "2.7.3" @@ -1148,68 +1151,68 @@ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== "@types/qs@*": - version "6.9.8" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.8.tgz#f2a7de3c107b89b441e071d5472e6b726b4adf45" - integrity sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg== + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== "@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== -"@types/semver@^7.3.12", "@types/semver@^7.5.0": - version "7.5.3" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" - integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== +"@types/semver@^7.3.12", "@types/semver@^7.5.6": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/send@*": - version "0.17.2" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.2.tgz#af78a4495e3c2b79bfbdac3955fdd50e03cc98f2" - integrity sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw== + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" "@types/node" "*" "@types/serve-static@*": - version "1.15.3" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.3.tgz#2cfacfd1fd4520bbc3e292cca432d5e8e2e3ee61" - integrity sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" - "@types/mime" "*" "@types/node" "*" + "@types/send" "*" "@types/sodium-native@^2.3.5": - version "2.3.6" - resolved "https://registry.yarnpkg.com/@types/sodium-native/-/sodium-native-2.3.6.tgz#2730191204978a1a96ec7de2f2653ef3e4f7927a" - integrity sha512-MMQ0aR90G9A8WiynSaNsUnzzlkw6akTqYz+OBEgSH/Y3+91X/bkkP3lOJROogLSQMoONM81IX49yVmakEWw6ZA== + version "2.3.9" + resolved "https://registry.yarnpkg.com/@types/sodium-native/-/sodium-native-2.3.9.tgz#50b790bd837aaf20c3880cb31b45244142ff00d4" + integrity sha512-jZIg5ltGH1okmnH3FrLQsgwjcjOVozMSHwSiEm1/LpMekhOMHbQqp21P4H24mizh1BjwI6Q8qmphmD/HJuAqWg== dependencies: "@types/node" "*" "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/uuid@^8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== -"@types/validator@^13.7.10": - version "13.11.2" - resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.2.tgz#a2502325a3c0bd29f36dbac3b763223edd801e17" - integrity sha512-nIKVVQKT6kGKysnNt+xLobr+pFJNssJRi2s034wgWeFBUx01fI8BeHTW2TcRp7VcFu9QCYG8IlChTuovcm0oKQ== +"@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/yargs-parser@*": - version "21.0.1" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.1.tgz#07773d7160494d56aa882d7531aac7319ea67c3b" - integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^16.0.0": - version "16.0.6" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.6.tgz#cc0c63684d68d23498cf0b5f32aa4c3fb437c638" - integrity sha512-oTP7/Q13GSPrgcwEwdlnkoZSQ1Hg9THe644qq8PG6hhJzjZ3qj1JjEFPIwWV/IXVs5XGIVqtkNOS9kh63WIJ+A== + version "16.0.9" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.9.tgz#ba506215e45f7707e6cbcaf386981155b7ab956e" + integrity sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA== dependencies: "@types/yargs-parser" "*" @@ -1297,16 +1300,23 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@whatwg-node/events@^0.1.0": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.1.2.tgz#23f7c7ad887d7fd448e9ce3261eac9ef319ddd7c" + integrity sha512-ApcWxkrs1WmEMS2CaLLFUEem/49erT3sxIVjpzU5f6zmVcnijtDSrhoK2zVobOIikZJdH63jdAXOrvjf6eOUNQ== + dependencies: + tslib "^2.6.3" + abab@^2.0.3, abab@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - accepts@~1.3.7, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -1334,19 +1344,21 @@ acorn-walk@^7.1.1: integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" 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.2.4, acorn@^8.4.1, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.11.0, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== agent-base@6: version "6.0.2" @@ -1383,9 +1395,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^3.2.1: version "3.2.1" @@ -1434,6 +1446,19 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + are-we-there-yet@~1.1.2: version "1.1.7" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" @@ -1469,28 +1494,29 @@ array-back@^4.0.1, array-back@^4.0.2: resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-includes@^3.1.6: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -1498,18 +1524,19 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" - integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" -array.prototype.flat@^1.3.1: +array.prototype.flat@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== @@ -1519,7 +1546,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -1529,17 +1556,18 @@ array.prototype.flatmap@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" async-retry@^1.2.1: @@ -1554,10 +1582,21 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axios@^1.6.5: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" babel-jest@^27.5.1: version "27.5.1" @@ -1595,22 +1634,25 @@ babel-plugin-jest-hoist@^27.5.1: "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-jest@^27.5.1: version "27.5.1" @@ -1636,25 +1678,16 @@ bignumber.js@9.0.0: integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== -bip32-ed25519@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/bip32-ed25519/-/bip32-ed25519-0.0.4.tgz#218943e212c2d3152dfd6f3a929305e3fe86534c" - integrity sha512-KfazzGVLwl70WZ1r98dO+8yaJRTGgWHL9ITn4bXHQi2mB4cT3Hjh53tXWUpEWE1zKCln7PbyX8Z337VapAOb5w== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: - bn.js "^5.1.1" - elliptic "^6.4.1" - hash.js "^1.1.7" - -bip39@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.1.0.tgz#c55a418deaf48826a6ceb34ac55b3ee1577e18a3" - integrity sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A== - dependencies: - "@noble/hashes" "^1.2.0" + file-uri-to-path "1.0.0" bl@^4.0.3: version "4.1.0" @@ -1665,16 +1698,6 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - body-parser@1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -1691,28 +1714,10 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -body-parser@^1.20.0, body-parser@^1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3, body-parser@^1.20.2: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -1722,7 +1727,7 @@ body-parser@^1.20.0, body-parser@^1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -1742,32 +1747,27 @@ brace-expansion@^2.0.1: 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" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + fill-range "^7.1.1" browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.21.9: - version "4.22.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.0.tgz#6adc8116589ccea8a99d0df79c5de2436199abdb" - integrity sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA== +browserslist@^4.23.1: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001539" - electron-to-chromium "^1.4.530" - node-releases "^2.0.13" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" bs-logger@0.x: version "0.2.6" @@ -1810,9 +1810,9 @@ builtins@^1.0.3: integrity sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ== builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== dependencies: semver "^7.0.0" @@ -1826,13 +1826,16 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -1849,10 +1852,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001539: - version "1.0.30001540" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001540.tgz#a316ca4f2ae673ab02ff0ec533334016d56ff658" - integrity sha512-9JL38jscuTJBTcuETxm8QLsFr/F6v0CYYTEU6r5+qSM98P2Q0Hmu0eG1dTG5GBUmywU3UlcVOUSIJYY47rdFSw== +caniuse-lite@^1.0.30001646: + version "1.0.30001662" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz#3574b22dfec54a3f3b6787331da1040fe8e763ec" + integrity sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA== chalk@^2.4.2: version "2.4.2" @@ -1882,9 +1885,9 @@ chardet@^0.7.0: 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" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -1901,24 +1904,29 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== class-validator@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159" - integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A== + 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.7.10" - libphonenumber-js "^1.10.14" - validator "^13.7.0" + "@types/validator" "^13.11.8" + libphonenumber-js "^1.10.53" + validator "^13.9.0" cli-cursor@^3.1.0: version "3.1.0" @@ -1962,6 +1970,25 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +cmake-js@^7.2.1: + version "7.3.0" + resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.3.0.tgz#6fd6234b7aeec4545c1c806f9e3f7ffacd9798b2" + integrity sha512-dXs2zq9WxrV87bpJ+WbnGKv8WUBXDw8blNiwNHoRe/it+ptscxhQHKB1SJXa1w+kocLMeP28Tk4/eTCezg4o+w== + dependencies: + axios "^1.6.5" + debug "^4" + fs-extra "^11.2.0" + lodash.isplainobject "^4.0.6" + memory-stream "^1.0.0" + node-api-headers "^1.1.0" + npmlog "^6.0.2" + rc "^1.2.7" + semver "^7.5.4" + tar "^6.2.0" + url-join "^4.0.1" + which "^2.0.2" + yargs "^17.7.2" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2001,6 +2028,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2035,6 +2067,11 @@ command-line-usage@^6.1.0: table-layout "^1.0.2" typical "^5.2.0" +commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2045,7 +2082,7 @@ consola@^3.2.3: resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== -console-control-strings@^1.0.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== @@ -2089,10 +2126,10 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== core-util-is@~1.0.0: version "1.0.3" @@ -2126,6 +2163,13 @@ cross-fetch@^3.1.5: dependencies: node-fetch "^2.6.12" +cross-inspect@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cross-inspect/-/cross-inspect-1.0.1.tgz#15f6f65e4ca963cf4cc1a2b5fef18f6ca328712b" + integrity sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A== + dependencies: + tslib "^2.4.0" + cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2166,18 +2210,43 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -date-fns@^2.29.3: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== dependencies: - "@babel/runtime" "^7.21.0" + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" date-format@^4.0.14: version "4.0.14" resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== +dayjs@^1.11.9: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2185,12 +2254,12 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, 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== +debug@4, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.2.7: version "3.2.7" @@ -2236,16 +2305,16 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-data-property@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" - integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - get-intrinsic "^1.2.1" + es-define-property "^1.0.0" + es-errors "^1.3.0" gopd "^1.0.1" - has-property-descriptors "^1.0.0" -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: +define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -2279,10 +2348,10 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -destr@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.1.tgz#2fc7bddc256fed1183e03f8d148391dde4023cb2" - integrity sha512-M1Ob1zPSIvlARiJUkKqvAZ3VAqQY6Jcuth/pBKQ2b1dX/Qx0OnJ8Vux6J2H5PTMQeRzWrrbTu70VxBfv/OPDJA== +destr@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" + integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== destroy@1.2.0: version "1.2.0" @@ -2362,49 +2431,41 @@ dotenv@10.0.0, dotenv@^10.0.0: integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== dotenv@^16.0.3: - version "16.3.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" - integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== dset@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a" - integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q== + version "3.1.4" + resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" + integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ebec@^1.1.0, ebec@^1.1.1: +ebec@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ebec/-/ebec-1.1.1.tgz#683a0dc82a77e86349e05b24c43d7233a6d0f840" integrity sha512-JZ1vcvPQtR+8LGbZmbjG21IxLQq/v47iheJqn2F6yB2CgnGfn8ZVg3myHrf3buIZS8UCwQK0jOSIb3oHX7aH8g== dependencies: smob "^1.4.0" +ebec@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/ebec/-/ebec-2.3.0.tgz#9b5b423f1196a0cd414e041111f2b1d146308bd5" + integrity sha512-bt+0tSL7223VU3PSVi0vtNLZ8pO1AfWolcPPMk2a/a5H+o/ZU9ky0n3A0zhrR4qzJTN61uPsGIO4ShhOukdzxA== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.530: - version "1.4.531" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.531.tgz#22966d894c4680726c17cf2908ee82ff5d26ac25" - integrity sha512-H6gi5E41Rn3/mhKlPaT1aIMg/71hTAqn0gYEllSuw9igNWtvQwu185jiCZoZD29n7Zukgh7GVZ3zGf0XvkhqjQ== - -elliptic@^6.4.1: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" +electron-to-chromium@^1.5.4: + version "1.5.26" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.26.tgz#449b4fa90e83ab98abbe3b6a96c8ee395de94452" + integrity sha512-Z+OMe9M/V6Ep9n/52+b7lkvYEps26z4Yz3vjWL1V61W0q+VLF1pOHhMY17sa4roz4AWmULSI8E6SAojZA5L0YQ== emittery@^0.8.1: version "0.8.1" @@ -2426,6 +2487,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -2433,14 +2499,21 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.12.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== +enhanced-resolve@^5.15.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" +envix@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/envix/-/envix-1.5.0.tgz#bbb7ceba6f098a272ef2044e606789844d08c1db" + integrity sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w== + dependencies: + std-env "^3.7.0" + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -2448,66 +2521,92 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1: - version "1.22.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" - integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.1" - get-symbol-description "^1.0.0" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.12" + is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.11" + which-typed-array "^1.1.15" -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: +es-define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: - has "^1.0.3" + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -2518,10 +2617,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.1, escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" @@ -2564,7 +2663,7 @@ eslint-config-standard@^17.0.0: resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== -eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -2574,29 +2673,30 @@ eslint-import-resolver-node@^0.3.7: resolve "^1.22.4" eslint-import-resolver-typescript@^3.5.4: - version "3.6.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" - integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - fast-glob "^3.3.1" - get-tsconfig "^4.5.0" - is-core-module "^2.11.0" + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" is-glob "^4.0.3" -eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== +eslint-module-utils@^2.8.1, eslint-module-utils@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4" + integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ== dependencies: debug "^3.2.7" eslint-plugin-dci-lint@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-dci-lint/-/eslint-plugin-dci-lint-0.3.0.tgz#dcd73c50505b589b415017cdb72716f98e9495c3" - integrity sha512-BhgrwJ5k3eMN41NwCZ/tYQGDTMOrHXpH8XOfRZrGtPqmlnOZCVGWow+KyZMz0/wOFVpXx/q9B0y7R7qtU7lnqg== + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-dci-lint/-/eslint-plugin-dci-lint-0.3.2.tgz#7ac9a9fb8e8c79b9b58267eb396e03a1430f09a7" + integrity sha512-I+hqMQ5Cbxrws9V3R7dC4p9hUDcZ0N1my+aBqteivGhgNDQp/RUQ63PhIgFZvL4KRiyBIZUPsmrXJMJjt0OVzw== eslint-plugin-es@^4.1.0: version "4.1.0" @@ -2607,32 +2707,33 @@ eslint-plugin-es@^4.1.0: regexpp "^3.0.0" eslint-plugin-import@^2.27.5: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== + version "2.30.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" + integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.9.0" + hasown "^2.0.2" + is-core-module "^2.15.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" semver "^6.3.1" - tsconfig-paths "^3.14.2" + tsconfig-paths "^3.15.0" eslint-plugin-jest@^27.2.1: - version "27.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.4.0.tgz#3926cca723c40c3d7a3fe0e1fd911eff5e681f50" - integrity sha512-ukVeKmMPAUA5SWjHenvyyXnirKfHKMdOsTZdn5tZx5EW05HGVQwBohigjFZGGj3zuv1cV6hc82FvWv6LdIbkgg== + version "27.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz#7c98a33605e1d8b8442ace092b60e9919730000b" + integrity sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -2658,9 +2759,9 @@ eslint-plugin-prettier@^4.2.1: prettier-linter-helpers "^1.0.0" eslint-plugin-promise@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" - integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + version "6.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" + integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== eslint-plugin-security@^1.7.1: version "1.7.1" @@ -2715,17 +2816,18 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.37.0: - version "8.50.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" - integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.50.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2772,9 +2874,9 @@ esprima@^4.0.0, esprima@^4.0.1: integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 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== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -2820,6 +2922,13 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execspawn@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/execspawn/-/execspawn-1.0.1.tgz#8286f9dde7cecde7905fbdc04e24f368f23f8da6" + integrity sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg== + dependencies: + util-extend "^1.0.1" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2841,14 +2950,14 @@ expect@^27.5.1: jest-message-util "^27.5.1" express-rate-limit@7: - version "7.1.5" - resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.5.tgz#af4c81143a945ea97f2599d13957440a0ddbfcfe" - integrity sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw== + version "7.4.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.4.0.tgz#5db412b8de83fa07ddb40f610c585ac8c1dab988" + integrity sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg== express-slow-down@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-2.0.1.tgz#60c4515467314675d89c54ec608e2d586aa30f87" - integrity sha512-zRogSZhNXJYKDBekhgFfFXGrOngH7Fub7Mx2g8OQ4RUBwSJP/3TVEKMgSGR/WlneT0mJ6NBUnidHhIELGVPe3w== + version "2.0.3" + resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-2.0.3.tgz#7b953a15c95105386d78370f8d172d88bb225dd6" + integrity sha512-vATCiFd8uQHtTeK5/Q0nLUukhZh+RV5zkcHxLQr0X5dEFVEYqzVXEe48nW23Z49fwtR+ApD9zn9sZRisTCR99w== dependencies: express-rate-limit "7" @@ -2889,36 +2998,36 @@ express@4.17.1: vary "~1.1.2" express@^4.17.1: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.1" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -2944,10 +3053,10 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.9, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.2.9, fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -2966,9 +3075,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== 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== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -2993,20 +3102,25 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -3050,11 +3164,11 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.2.7" + flatted "^3.2.9" keyv "^4.5.3" rimraf "^3.0.2" @@ -3063,10 +3177,15 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.2.7: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== +flatted@^3.2.7, flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== for-each@^0.3.3: version "0.3.3" @@ -3076,9 +3195,9 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -3116,6 +3235,15 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@^11.2.0: + version "11.2.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -3125,6 +3253,13 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3135,10 +3270,10 @@ fsevents@^2.3.2, fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.6: version "1.1.6" @@ -3155,6 +3290,20 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3186,15 +3335,16 @@ get-caller-file@^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-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + es-errors "^1.3.0" + function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-package-type@^0.1.0: version "0.1.0" @@ -3206,18 +3356,19 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" -get-tsconfig@^4.5.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== dependencies: resolve-pkg-maps "^1.0.0" @@ -3247,16 +3398,17 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.3.3: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.3" @@ -3270,35 +3422,25 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.1.0: - 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" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.22.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.22.0.tgz#0c9fcb9c48a2494fbb5edbfee644285543eba9d8" - integrity sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -3324,6 +3466,16 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +"gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js#master": + version "0.0.1" + resolved "git+https://github.com/gradido/gradido-blockchain-js#02aaeefc015c8ec8b1a2c453d75e7c2cf803a7c2" + dependencies: + bindings "^1.5.0" + nan "^2.20.0" + node-addon-api "^7.1.1" + node-gyp-build "^4.8.1" + prebuildify "git+https://github.com/einhornimmond/prebuildify#cmake_js" + graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" @@ -3345,23 +3497,16 @@ graphql-request@^6.1.0: cross-fetch "^3.1.5" graphql-scalars@^1.22.2: - version "1.22.2" - resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.22.2.tgz#6326e6fe2d0ad4228a9fea72a977e2bf26b86362" - integrity sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ== + version "1.23.0" + resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.23.0.tgz#486785d1a6f9449277054a92afc7e1fb73f459d6" + integrity sha512-YTRNcwitkn8CqYcleKOx9IvedA8JIERn8BRq21nlKgOr4NEcTaWEG0sT+H92eF3ALTFbPgsqfft4cw+MGgv0Gg== dependencies: tslib "^2.5.0" -graphql-subscriptions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz#11ec181d475852d8aec879183e8e1eb94f2eb79a" - integrity sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA== - dependencies: - iterall "^1.3.0" - graphql@^16.7.1: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + version "16.9.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" + integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== handlebars@^4.7.6: version "4.7.8" @@ -3390,49 +3535,41 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.1.1" + es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" + has-symbols "^1.0.3" -has-unicode@^2.0.0: +has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: - function-bind "^1.1.1" - -hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" + function-bind "^1.1.2" helmet@^7.1.0: version "7.1.0" @@ -3444,15 +3581,6 @@ highlight.js@^10.7.1: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -3545,9 +3673,9 @@ ignore-by-default@^1.0.1: integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-fresh@^3.2.1: version "3.3.0" @@ -3558,9 +3686,9 @@ import-fresh@^3.2.1: resolve-from "^4.0.0" import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -3617,13 +3745,13 @@ inquirer@^7.3.3: strip-ansi "^6.0.0" through "^2.3.6" -internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + es-errors "^1.3.0" + hasown "^2.0.0" side-channel "^1.0.4" ipaddr.js@1.9.1: @@ -3631,14 +3759,13 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" + get-intrinsic "^1.2.1" is-arrayish@^0.2.1: version "0.2.1" @@ -3667,17 +3794,31 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-bun-module@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.2.1.tgz#495e706f42e29f086fd5fe1ac3c51f106062b9fc" + integrity sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q== + dependencies: + semver "^7.6.3" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - has "^1.0.3" + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" is-date-object@^1.0.1: version "1.0.5" @@ -3715,10 +3856,10 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -3755,12 +3896,12 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -3781,12 +3922,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - which-typed-array "^1.1.11" + which-typed-array "^1.1.14" is-typedarray@^1.0.0: version "1.0.0" @@ -3816,9 +3957,9 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: version "5.2.1" @@ -3850,22 +3991,17 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - -jackspeak@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.5.tgz#443f237f9eeeb0d7c6ec34835ef5289bb4acb068" - integrity sha512-Ratx+B8WeXLAtRJn26hrhY8S1+Jz6pxPMrkrdkgb/NstTNiqMhX0/oFVu5wX+g5n6JlEu2LPsDJmY8nRP4+alw== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -4276,15 +4412,15 @@ jest@^27.2.4: import-local "^3.0.2" jest-cli "^27.5.1" -jiti@^1.19.3: - version "1.20.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" - integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== +jiti@^1.21.6: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== jose@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.2.tgz#b91170e9ba6dbe609b0c0a86568f9a1fbe4335c0" - integrity sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg== + version "5.9.2" + resolved "https://registry.yarnpkg.com/jose/-/jose-5.9.2.tgz#22a22da06edb8fb9e583aa24bafc1e8457b4db92" + integrity sha512-ILI2xx/I57b20sd7rHZvgiiQrmp2mcotwsAH+5ajbpFQbrYVQdNHYlQhoA5cFb78CgtBOxtC05TeA+mcgkuCqQ== js-tokens@^4.0.0: version "4.0.0" @@ -4383,10 +4519,19 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" @@ -4408,10 +4553,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libphonenumber-js@^1.10.14: - version "1.10.44" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.44.tgz#6709722461173e744190494aaaec9c1c690d8ca8" - integrity sha512-svlRdNBI5WgBjRC20GrCfbFiclbF0Cx+sCcQob/C1r57nsoq0xg8r65QbTyVyweQIlB33P+Uahyho6EMYgcOyQ== +libphonenumber-js@^1.10.53: + version "1.11.8" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.8.tgz#697fdd36500a97bc672d7927d867edf34b4bd2a7" + integrity sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg== lines-and-columns@^1.1.6: version "1.2.4" @@ -4432,16 +4577,17 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -locter@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/locter/-/locter-1.2.2.tgz#a52e870236cd9383c1e0e3012f33a4c3f2a6f9d8" - integrity sha512-9C/TDHlFdZUlVtBXUmpXhHaO4V9uGYqWKIHag+2ToPQ22j3VEqg7tz8ZI1iWkHmBUGXS4wKXavzWATwFjxhirw== +locter@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/locter/-/locter-2.1.1.tgz#31be1c81db8268162c4c3e4d2700df3f7ed235cc" + integrity sha512-trTg69NVZkfo/70BW7cXAZkFEFDWlQwPcNUO1aDZs/HhOzt7jBPSWldGqK/RXQDmb2tWCpPdRmrHMSXPRm3B2w== dependencies: - destr "^2.0.0" - ebec "^1.1.1" + destr "^2.0.3" + ebec "^2.3.0" + fast-glob "^3.3.2" flat "^5.0.2" - glob "^10.3.3" - jiti "^1.19.3" + jiti "^1.21.6" + yaml "^2.5.0" lodash.camelcase@^4.3.0: version "4.3.0" @@ -4453,6 +4599,11 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -4485,20 +4636,15 @@ log4js@^6.7.1: streamroller "^3.1.5" loglevel@^1.6.8: - version "1.8.1" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" - integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== + version "1.9.2" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" + integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -long@^5.0.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== - lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -4506,6 +4652,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4525,11 +4676,6 @@ lru-cache@^7.10.1, lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -"lru-cache@^9.1.1 || ^10.0.0": - version "10.0.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" - integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== - make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -4559,11 +4705,23 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== +memory-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/memory-stream/-/memory-stream-1.0.0.tgz#481dfd259ccdf57b03ec2c9632960044180e73c2" + integrity sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww== + dependencies: + readable-stream "^3.4.0" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -4580,11 +4738,11 @@ methods@~1.1.2: integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 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== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -4614,16 +4772,6 @@ mimic-response@^2.0.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -4631,17 +4779,10 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, 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" - -minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" @@ -4650,16 +4791,41 @@ minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" - integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mkdirp@^2.1.3: version "2.1.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" @@ -4675,12 +4841,7 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4730,6 +4891,11 @@ named-placeholders@^1.1.2: dependencies: lru-cache "^7.14.1" +nan@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== + napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -4790,11 +4956,28 @@ node-abi@^2.21.0: dependencies: semver "^5.4.1" +node-abi@^3.3.0: + version "3.68.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.68.0.tgz#8f37fb02ecf4f43ebe694090dcb52e0c4cc4ba25" + integrity sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A== + dependencies: + semver "^7.3.5" + node-abort-controller@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + +node-api-headers@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.3.0.tgz#bb32c6b3e33fb0004bd93c66787bf00998c834ea" + integrity sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg== + node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4802,20 +4985,20 @@ node-fetch@^2.6.12, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.6.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" - integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== +node-gyp-build@^4.8.1: + version "4.8.2" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" + integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw== node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== nodemon@^2.0.20: version "2.0.22" @@ -4833,18 +5016,25 @@ nodemon@^2.0.20: touch "^3.1.0" undefsafe "^2.0.5" -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== - dependencies: - abbrev "1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-path@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" + integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== + dependencies: + which "^1.2.10" + +npm-run-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -4852,6 +5042,15 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-which@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" + integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== + dependencies: + commander "^2.9.0" + npm-path "^2.0.2" + which "^1.2.10" + npmlog@^4.0.1: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -4862,68 +5061,78 @@ npmlog@^4.0.1: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + version "2.2.12" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" + integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" + call-bind "^1.0.5" + define-properties "^1.2.1" has-symbols "^1.0.3" object-keys "^1.1.1" -object.fromentries@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.groupby@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" - integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" -object.values@^1.1.6: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== +object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" on-finished@2.4.1: version "2.4.1" @@ -4954,16 +5163,16 @@ onetime@^5.1.0, onetime@^5.1.2: mimic-fn "^2.1.0" optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" os-tmpdir@~1.0.2: version "1.0.2" @@ -5003,6 +5212,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5070,14 +5284,19 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" - integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - lru-cache "^9.1.1 || ^10.0.0" + lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + 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" @@ -5088,10 +5307,10 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -5110,6 +5329,11 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + prebuild-install@^6.1.2: version "6.1.4" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.4.tgz#ae3c0142ad611d58570b89af4986088a4937e00f" @@ -5129,6 +5353,20 @@ prebuild-install@^6.1.2: tar-fs "^2.0.0" tunnel-agent "^0.6.0" +"prebuildify@git+https://github.com/einhornimmond/prebuildify#cmake_js": + version "6.0.1" + resolved "git+https://github.com/einhornimmond/prebuildify#91f4e765611fcc1e8123df0c8fc84aec5ab55b31" + dependencies: + cmake-js "^7.2.1" + execspawn "^1.0.1" + minimist "^1.2.5" + mkdirp-classic "^0.5.3" + node-abi "^3.3.0" + npm-run-path "^3.1.0" + npm-which "^3.0.1" + pump "^3.0.0" + tar-fs "^2.1.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -5168,24 +5406,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@^7.2.5: - version "7.2.5" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d" - integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - proxy-addr@~2.0.5, proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -5194,6 +5414,11 @@ proxy-addr@~2.0.5, proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.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== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -5205,24 +5430,24 @@ pstree.remy@^1.1.8: integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" once "^1.3.1" punycode@^2.1.0, punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" qs@6.7.0: version "6.7.0" @@ -5262,16 +5487,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - raw-body@2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" @@ -5323,7 +5538,7 @@ readable-stream@^2.0.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -5345,28 +5560,29 @@ reduce-flatten@^2.0.0: integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== reflect-metadata@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + version "0.1.14" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859" + integrity sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A== -regenerator-runtime@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" - integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== +reflect-metadata@^0.2.1, reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== regexp-tree@~0.1.1: version "0.1.27" resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== -regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" regexpp@^3.0.0: version "3.2.0" @@ -5411,9 +5627,9 @@ resolve.exports@^1.1.0: integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.4: - version "1.22.6" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" - integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" path-parse "^1.0.7" @@ -5438,9 +5654,9 @@ reusify@^1.0.4: integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" @@ -5468,13 +5684,13 @@ rxjs@^6.6.0: dependencies: tslib "^1.9.0" -safe-array-concat@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" has-symbols "^1.0.3" isarray "^2.0.5" @@ -5488,13 +5704,13 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" + call-bind "^1.0.6" + es-errors "^1.3.0" is-regex "^1.1.4" safe-regex@^2.1.1: @@ -5516,12 +5732,10 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -semver@7.x, semver@^7.0.0, semver@^7.3.2, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: - 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.x, semver@^7.0.0, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== semver@^5.4.1, semver@^5.7.1: version "5.7.2" @@ -5557,10 +5771,10 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -5591,29 +5805,42 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -set-function-name@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" setprototypeof@1.1.1: version "1.1.1" @@ -5645,16 +5872,17 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5695,17 +5923,10 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -smob@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/smob/-/smob-1.4.1.tgz#66270e7df6a7527664816c5b577a23f17ba6f5b5" - integrity sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ== - -sodium-native@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.0.4.tgz#561b7c39c97789f8202d6fd224845fe2e8cd6879" - integrity sha512-faqOKw4WQKK7r/ybn6Lqo1F9+L5T6NlBJJYvpxbZPetpWylUVqz449mvlwIBKBqxEHbWakWuOlUt8J3Qpc4sWw== - dependencies: - node-gyp-build "^4.6.0" +smob@^1.4.0, smob@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" + integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== source-map-support@^0.5.6: version "0.5.21" @@ -5734,9 +5955,9 @@ spdx-correct@^3.0.0: spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== spdx-expression-parse@^3.0.0: version "3.0.1" @@ -5747,9 +5968,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.15" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz#142460aabaca062bc7cd4cc87b7d50725ed6a4ba" - integrity sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ== + version "3.0.20" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89" + integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw== sprintf-js@~1.0.2: version "1.0.3" @@ -5783,6 +6004,11 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== +std-env@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + streamroller@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" @@ -5800,7 +6026,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": 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== @@ -5818,6 +6044,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, 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== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -5827,32 +6062,33 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -5868,7 +6104,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5882,6 +6118,13 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -5968,7 +6211,7 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-fs@^2.0.0: +tar-fs@^2.0.0, tar-fs@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -5989,6 +6232,18 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -6075,16 +6330,14 @@ toml@^3.0.0: integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" + version "3.1.1" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" + integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -6118,17 +6371,17 @@ ts-jest@^27.0.5: yargs-parser "20.x" ts-mysql-migrate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ts-mysql-migrate/-/ts-mysql-migrate-1.0.2.tgz#736d37c3aa3fef92f226b869098e939950d0e18c" - integrity sha512-zDW6iQsfPCJfQ3JMhfUGjhy8aK+VNTvPrXmJH66PB2EGEvyn4m7x2nBdhDNhKuwYU9LMxW1p+l39Ei+btXNpxA== + version "1.1.2" + resolved "https://registry.yarnpkg.com/ts-mysql-migrate/-/ts-mysql-migrate-1.1.2.tgz#6f280f4684cb95440ffa7254b926b494badb8cf3" + integrity sha512-jwhVaMrYBNNhAoZ5XISxzqbnXTHqwazqu/r1UQ6kUaGNPGL43ZFnBiXVj4Gm3pfe3xtCGIaNInehDfdDuigPgw== dependencies: "@types/mysql" "^2.15.8" mysql "^2.18.1" ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -6149,10 +6402,10 @@ ts-typed-json@^0.3.2: resolved "https://registry.yarnpkg.com/ts-typed-json/-/ts-typed-json-0.3.2.tgz#f4f20f45950bae0a383857f7b0a94187eca1b56a" integrity sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA== -tsconfig-paths@^3.14.2: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.2" @@ -6173,10 +6426,10 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.0.3, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.2, tslib@^2.6.2, tslib@^2.6.3: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== tsutils@^3.21.0: version "3.21.0" @@ -6215,16 +6468,16 @@ type-fest@^0.21.3: integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-graphql@^2.0.0-beta.2: - version "2.0.0-beta.3" - resolved "https://registry.yarnpkg.com/type-graphql/-/type-graphql-2.0.0-beta.3.tgz#71a796845dbb3f3cca5dfb97a38ffe30ee5aa1ea" - integrity sha512-5HEiQaWHPYhPmbJuMmT+IZgjsnbNWsW37osUISwgr5EpcHZ4krLl8eBoOfjFya4mxAWYshlpSO1ahaucJQqM5g== + version "2.0.0-rc.2" + resolved "https://registry.yarnpkg.com/type-graphql/-/type-graphql-2.0.0-rc.2.tgz#1086ef889737bd21a9f0ed0fb1041dce2d918e92" + integrity sha512-DJ8erG1cmjteMrOhFIkBHOqRM+L+wCJxvNjbbj1Y+q2r4HZkB1qOSS4ZD4AaoAfRPAp1yU23gMtmzf0jen/FFA== dependencies: - "@types/node" "^20.4.9" - "@types/semver" "^7.5.0" + "@graphql-yoga/subscription" "^5.0.0" + "@types/node" "^20.14.0" + "@types/semver" "^7.5.6" graphql-query-complexity "^0.12.0" - graphql-subscriptions "^2.0.0" semver "^7.5.4" - tslib "^2.6.0" + tslib "^2.6.2" type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" @@ -6234,44 +6487,49 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typedarray-to-buffer@^3.1.5: version "3.1.5" @@ -6281,35 +6539,36 @@ typedarray-to-buffer@^3.1.5: is-typedarray "^1.0.0" typeorm-extension@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/typeorm-extension/-/typeorm-extension-3.0.2.tgz#34e7256bc24e070b204442ff497a5d28e38341e5" - integrity sha512-hV67zcFuJo1o3mslgbPTwCQMeMKAsV4ZcdPZiXDrbY+km6rdsbhIycn1iRfSfbb69aHeKPcbc/tpdJLXsdhBqg== + version "3.6.1" + resolved "https://registry.yarnpkg.com/typeorm-extension/-/typeorm-extension-3.6.1.tgz#e40711951db48ed59e22ccdebcc43d5527acf5e8" + integrity sha512-OyjYrjtu2VgtjU1vJiUcQ5A+auNWgUtSBfZ4rWgMdsBBkzGpOjFKkPrA6B2RdngJfk9KOGNaw34XI0EATw+LqQ== dependencies: - "@faker-js/faker" "^8.0.2" + "@faker-js/faker" "^8.4.1" consola "^3.2.3" - locter "^1.2.2" + envix "^1.5.0" + locter "^2.1.0" pascal-case "^3.1.2" rapiq "^0.9.0" - reflect-metadata "^0.1.13" - smob "^1.4.0" + reflect-metadata "^0.2.2" + smob "^1.5.0" yargs "^17.7.2" typeorm@^0.3.16, typeorm@^0.3.17: - version "0.3.17" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.17.tgz#a73c121a52e4fbe419b596b244777be4e4b57949" - integrity sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig== + version "0.3.20" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab" + integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q== dependencies: "@sqltools/formatter" "^1.2.5" app-root-path "^3.1.0" buffer "^6.0.3" chalk "^4.1.2" cli-highlight "^2.1.11" - date-fns "^2.29.3" + dayjs "^1.11.9" debug "^4.3.4" dotenv "^16.0.3" - glob "^8.1.0" + glob "^10.3.10" mkdirp "^2.1.3" - reflect-metadata "^0.1.13" + reflect-metadata "^0.2.1" sha.js "^2.4.11" tslib "^2.5.0" uuid "^9.0.0" @@ -6331,9 +6590,9 @@ typical@^5.2.0: integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== uglify-js@^3.1.4: - version "3.17.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" - integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== unbox-primitive@^1.0.2: version "1.0.2" @@ -6350,10 +6609,15 @@ undefsafe@^2.0.5: resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== -undici-types@~5.25.1: - version "5.25.3" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" - integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== universalify@^0.1.0: version "0.1.2" @@ -6365,18 +6629,23 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2: version "4.4.1" @@ -6385,6 +6654,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + url-parse@^1.5.3: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" @@ -6398,6 +6672,11 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + integrity sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA== + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -6442,10 +6721,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -validator@^13.7.0: - version "13.11.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" - integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== +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.12: version "1.0.12" @@ -6538,31 +6817,43 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.11: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" + has-tostringtag "^1.0.2" -which@^2.0.1: +which@^1.2.10: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: 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" -wide-align@^1.1.0: +wide-align@^1.1.0, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: string-width "^1.0.2 || 2 || 3 || 4" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -6576,7 +6867,16 @@ wordwrapjs@^4.0.0: reduce-flatten "^2.0.0" typical "^5.2.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -6610,9 +6910,9 @@ write-file-atomic@^3.0.0: typedarray-to-buffer "^3.1.5" ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== xml-name-validator@^3.0.0: version "3.0.0" @@ -6639,6 +6939,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" + integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== + yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts b/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts index c84a15f41..77744a6d4 100644 --- a/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts +++ b/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts @@ -2,7 +2,8 @@ import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, ManyToOne, JoinColu import { Decimal } from 'decimal.js-light' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Transaction } from '../Transaction' +// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked +import { Transaction } from './Transaction' @Entity('backend_transactions') export class BackendTransaction extends BaseEntity { diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts b/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts index 4947c2a2d..b520b27f8 100644 --- a/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts +++ b/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts @@ -13,7 +13,8 @@ import { Decimal } from 'decimal.js-light' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { Account } from '../Account' import { Community } from '../Community' -import { BackendTransaction } from '../BackendTransaction' +// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked +import { BackendTransaction } from './BackendTransaction' @Entity('transactions') export class Transaction extends BaseEntity { diff --git a/dlt-database/entity/0004-fix_spelling/Transaction.ts b/dlt-database/entity/0004-fix_spelling/Transaction.ts index 4d5a304da..f3f4427f7 100644 --- a/dlt-database/entity/0004-fix_spelling/Transaction.ts +++ b/dlt-database/entity/0004-fix_spelling/Transaction.ts @@ -13,7 +13,8 @@ import { Decimal } from 'decimal.js-light' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { Account } from '../Account' import { Community } from '../Community' -import { BackendTransaction } from '../BackendTransaction' +// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked +import { BackendTransaction } from '../0003-refactor_transaction_recipe/BackendTransaction' @Entity('transactions') export class Transaction extends BaseEntity { diff --git a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts new file mode 100644 index 000000000..f19790ff1 --- /dev/null +++ b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts @@ -0,0 +1,64 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + JoinColumn, + OneToOne, + OneToMany, + BaseEntity, +} from 'typeorm' +import { Account } from '../Account' +import { Transaction } from '../Transaction' +import { AccountCommunity } from '../AccountCommunity' + +@Entity('communities') +export class Community extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'iota_topic', collation: 'utf8mb4_unicode_ci', unique: true }) + iotaTopic: string + + @Column({ name: 'root_pubkey', type: 'binary', length: 32, unique: true, nullable: true }) + rootPubkey?: Buffer + + @Column({ name: 'root_privkey', type: 'binary', length: 80, nullable: true }) + rootEncryptedPrivkey?: Buffer + + @Column({ name: 'root_chaincode', type: 'binary', length: 32, nullable: true }) + rootChaincode?: Buffer + + @Column({ type: 'tinyint', default: true }) + foreign: boolean + + @Column({ name: 'gmw_account_id', type: 'int', unsigned: true, nullable: true }) + gmwAccountId?: number + + @OneToOne(() => Account, { cascade: true }) + @JoinColumn({ name: 'gmw_account_id' }) + gmwAccount?: Account + + @Column({ name: 'auf_account_id', type: 'int', unsigned: true, nullable: true }) + aufAccountId?: number + + @OneToOne(() => Account, { cascade: true }) + @JoinColumn({ name: 'auf_account_id' }) + aufAccount?: Account + + @Column({ name: 'created_at', type: 'datetime', precision: 3 }) + createdAt: Date + + // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here + @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) + confirmedAt?: Date + + @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.community) + @JoinColumn({ name: 'community_id' }) + accountCommunities: AccountCommunity[] + + @OneToMany(() => Transaction, (transaction) => transaction.community) + transactions?: Transaction[] + + @OneToMany(() => Transaction, (transaction) => transaction.otherCommunity) + friendCommunitiesTransactions?: Transaction[] +} diff --git a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts new file mode 100644 index 000000000..eae5a6405 --- /dev/null +++ b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts @@ -0,0 +1,109 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + OneToOne, + JoinColumn, + BaseEntity, +} from 'typeorm' + +import { Account } from '../Account' +import { Community } from '../Community' + +@Entity('transactions') +export class Transaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) + id: number + + @Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true }) + iotaMessageId?: Buffer + + @OneToOne(() => Transaction, { cascade: ['update'] }) + // eslint-disable-next-line no-use-before-define + pairingTransaction?: Transaction + + @Column({ name: 'pairing_transaction_id', type: 'bigint', unsigned: true, nullable: true }) + pairingTransactionId?: number + + // if transaction has a sender than it is also the sender account + @ManyToOne(() => Account, (account) => account.transactionSigning) + @JoinColumn({ name: 'signing_account_id' }) + signingAccount?: Account + + @Column({ name: 'signing_account_id', type: 'int', unsigned: true, nullable: true }) + signingAccountId?: number + + @ManyToOne(() => Account, (account) => account.transactionRecipient) + @JoinColumn({ name: 'recipient_account_id' }) + recipientAccount?: Account + + @Column({ name: 'recipient_account_id', type: 'int', unsigned: true, nullable: true }) + recipientAccountId?: number + + @ManyToOne(() => Community, (community) => community.transactions, { + eager: true, + }) + @JoinColumn({ name: 'community_id' }) + community: Community + + @Column({ name: 'community_id', type: 'int', unsigned: true }) + communityId: number + + @ManyToOne(() => Community, (community) => community.friendCommunitiesTransactions) + @JoinColumn({ name: 'other_community_id' }) + otherCommunity?: Community + + @Column({ name: 'other_community_id', type: 'int', unsigned: true, nullable: true }) + otherCommunityId?: number + + @Column({ + type: 'bigint', + nullable: true, + }) + amount?: number + + // account balance for sender based on creation date + @Column({ + name: 'account_balance_on_creation', + type: 'bigint', + nullable: true, + }) + accountBalanceOnCreation?: number + + @Column({ type: 'tinyint' }) + type: number + + @Column({ name: 'created_at', type: 'datetime', precision: 3 }) + createdAt: Date + + @Column({ name: 'body_bytes', type: 'blob' }) + bodyBytes: Buffer + + @Column({ type: 'binary', length: 64, unique: true }) + signature: Buffer + + @Column({ name: 'protocol_version', type: 'varchar', length: 255, default: '1' }) + protocolVersion: string + + @Column({ type: 'bigint', nullable: true }) + nr?: number + + @Column({ name: 'running_hash', type: 'binary', length: 48, nullable: true }) + runningHash?: Buffer + + // account balance for sender based on confirmation date (iota milestone) + @Column({ + name: 'account_balance_on_confirmation', + type: 'bigint', + nullable: true, + }) + accountBalanceOnConfirmation?: number + + @Column({ name: 'iota_milestone', type: 'bigint', nullable: true }) + iotaMilestone?: number + + // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here + @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) + confirmedAt?: Date +} diff --git a/dlt-database/entity/BackendTransaction.ts b/dlt-database/entity/BackendTransaction.ts deleted file mode 100644 index 6ec68427d..000000000 --- a/dlt-database/entity/BackendTransaction.ts +++ /dev/null @@ -1 +0,0 @@ -export { BackendTransaction } from './0003-refactor_transaction_recipe/BackendTransaction' diff --git a/dlt-database/entity/Community.ts b/dlt-database/entity/Community.ts index cb4d34c43..e31bb1e5a 100644 --- a/dlt-database/entity/Community.ts +++ b/dlt-database/entity/Community.ts @@ -1 +1 @@ -export { Community } from './0003-refactor_transaction_recipe/Community' +export { Community } from './0005-refactor_with_gradido_blockchain_lib/Community' diff --git a/dlt-database/entity/Transaction.ts b/dlt-database/entity/Transaction.ts index 9db8e6747..4c22b275f 100644 --- a/dlt-database/entity/Transaction.ts +++ b/dlt-database/entity/Transaction.ts @@ -1 +1 @@ -export { Transaction } from './0004-fix_spelling/Transaction' +export { Transaction } from './0005-refactor_with_gradido_blockchain_lib/Transaction' diff --git a/dlt-database/entity/index.ts b/dlt-database/entity/index.ts index b1215263d..ba7ea2663 100644 --- a/dlt-database/entity/index.ts +++ b/dlt-database/entity/index.ts @@ -1,6 +1,5 @@ import { Account } from './Account' import { AccountCommunity } from './AccountCommunity' -import { BackendTransaction } from './BackendTransaction' import { Community } from './Community' import { InvalidTransaction } from './InvalidTransaction' import { Migration } from './Migration' @@ -10,7 +9,6 @@ import { User } from './User' export const entities = [ AccountCommunity, Account, - BackendTransaction, Community, InvalidTransaction, Migration, diff --git a/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts b/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts new file mode 100644 index 000000000..453c131ba --- /dev/null +++ b/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts @@ -0,0 +1,28 @@ +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + `ALTER TABLE \`communities\` CHANGE COLUMN \`root_privkey\` \`root_encrypted_privkey\` binary(80) NULL DEFAULT NULL;`, + ) + await queryFn( + `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_confirmation\` int NULL DEFAULT 0;`, + ) + await queryFn( + `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_creation\` int NULL DEFAULT 0;`, + ) + await queryFn(`ALTER TABLE \`transactions\` MODIFY COLUMN \`amount\` int NULL DEFAULT 0;`) + await queryFn(`DROP TABLE \`backend_transactions\`;`) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + `ALTER TABLE \`communities\` CHANGE COLUMN \`root_encrypted_privkey\` \`root_privkey\` binary(64) NULL DEFAULT NULL;`, + ) + await queryFn( + `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_confirmation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000;`, + ) + await queryFn( + `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_creation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000;`, + ) + await queryFn( + `ALTER TABLE \`transactions\` MODIFY COLUMN \`amount\` decimal(40, 20) NULL DEFAULT NULL;`, + ) +} diff --git a/dlt-database/yarn.lock b/dlt-database/yarn.lock index ac35e1eaa..f4e8c4086 100644 --- a/dlt-database/yarn.lock +++ b/dlt-database/yarn.lock @@ -2,24 +2,12 @@ # yarn lockfile v1 -"@babel/runtime@^7.21.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" - integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== +"@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" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: - regenerator-runtime "^0.13.11" - -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" - integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" + "@jridgewell/trace-mapping" "0.3.9" "@eslint-community/eslint-plugin-eslint-comments@^3.2.1": version "3.2.1" @@ -36,19 +24,19 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" - integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" + integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== -"@eslint/eslintrc@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" - integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.5.2" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -56,18 +44,18 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.42.0": - version "8.42.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.42.0.tgz#484a1d638de2911e6f5a30c12f49c7e4a3270fb6" - integrity sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw== +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -75,10 +63,40 @@ 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== +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -101,17 +119,15 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/utils@^2.3.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.1.tgz#adf291d0357834c410ce80af16e711b56c7b1cd3" - integrity sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w== - dependencies: - cross-spawn "^7.0.3" - fast-glob "^3.2.12" - is-glob "^4.0.3" - open "^9.1.0" - picocolors "^1.0.0" - tslib "^2.5.0" +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@sqltools/formatter@^1.2.5": version "1.2.5" @@ -119,24 +135,24 @@ integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== "@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/faker@^5.5.9": version "5.5.9" @@ -144,9 +160,9 @@ integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA== "@types/json-schema@^7.0.9": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" @@ -154,26 +170,28 @@ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/mysql@^2.15.8": - version "2.15.19" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.19.tgz#d158927bb7c1a78f77e56de861a3b15cae0e7aed" - integrity sha512-wSRg2QZv14CWcZXkgdvHbbV2ACufNy5EgI8mBBxnJIptchv7DBy/h53VMa2jDhyo0C9MO4iowE6z9vF8Ja1DkQ== + version "2.15.26" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" + integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== dependencies: "@types/node" "*" "@types/node@*": - version "16.7.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.1.tgz#c6b9198178da504dfca1fd0be9b2e1002f1586f0" - integrity sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A== + version "22.5.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793" + integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg== + dependencies: + undici-types "~6.19.2" "@types/node@^16.10.3": - version "16.10.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5" - integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ== + version "16.18.106" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.106.tgz#62228200da6d98365d2de5601f7230cdf041f0e2" + integrity sha512-YTgQUcpdXRc7iiEMutkkXl9WUx5lGUCVYvnfRg9CV+IA4l9epctEhCTbaw4KgzXaKYv8emvFJkEM65+MkNUhsQ== "@types/semver@^7.3.12": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/uuid@^8.3.4": version "8.3.4" @@ -181,110 +199,112 @@ integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@typescript-eslint/eslint-plugin@^5.57.1": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz#2604cfaf2b306e120044f901e20c8ed926debf15" - integrity sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA== + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" + integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.9" - "@typescript-eslint/type-utils" "5.59.9" - "@typescript-eslint/utils" "5.59.9" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/type-utils" "5.62.0" + "@typescript-eslint/utils" "5.62.0" debug "^4.3.4" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" natural-compare-lite "^1.4.0" semver "^7.3.7" tsutils "^3.21.0" "@typescript-eslint/parser@^5.57.1": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.9.tgz#a85c47ccdd7e285697463da15200f9a8561dd5fa" - integrity sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ== + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" + integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== dependencies: - "@typescript-eslint/scope-manager" "5.59.9" - "@typescript-eslint/types" "5.59.9" - "@typescript-eslint/typescript-estree" "5.59.9" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.59.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz#eadce1f2733389cdb58c49770192c0f95470d2f4" - integrity sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ== +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== dependencies: - "@typescript-eslint/types" "5.59.9" - "@typescript-eslint/visitor-keys" "5.59.9" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/type-utils@5.59.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz#53bfaae2e901e6ac637ab0536d1754dfef4dafc2" - integrity sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q== +"@typescript-eslint/type-utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" + integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== dependencies: - "@typescript-eslint/typescript-estree" "5.59.9" - "@typescript-eslint/utils" "5.59.9" + "@typescript-eslint/typescript-estree" "5.62.0" + "@typescript-eslint/utils" "5.62.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.59.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.9.tgz#3b4e7ae63718ce1b966e0ae620adc4099a6dcc52" - integrity sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/typescript-estree@5.59.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz#6bfea844e468427b5e72034d33c9fffc9557392b" - integrity sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA== +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== dependencies: - "@typescript-eslint/types" "5.59.9" - "@typescript-eslint/visitor-keys" "5.59.9" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.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.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.9.tgz#adee890107b5ffe02cd46fdaa6c2125fb3c6c7c4" - integrity sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg== +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== 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.9" - "@typescript-eslint/types" "5.59.9" - "@typescript-eslint/typescript-estree" "5.59.9" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.59.9": - version "5.59.9" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz#9f86ef8e95aca30fb5a705bb7430f95fc58b146d" - integrity sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q== +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== dependencies: - "@typescript-eslint/types" "5.59.9" + "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + 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== acorn-walk@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.1.tgz#3ddab7f84e4a7e2313f6c414c5b7dac85f4e3ebc" - integrity sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w== + version "8.3.3" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" + integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + dependencies: + acorn "^8.11.0" -acorn@^8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" - integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -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== - -ajv@^6.10.0, ajv@^6.12.4: +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== @@ -294,16 +314,16 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + 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" @@ -311,10 +331,15 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== app-root-path@^3.1.0: version "3.1.0" @@ -331,23 +356,24 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" -array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== +array-includes@^3.1.7: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -355,30 +381,58 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== +array.prototype.findlastindex@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" balanced-match@^1.0.0: version "1.0.2" @@ -390,23 +444,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -big-integer@^1.6.44: - version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== - bignumber.js@9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== -bplist-parser@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" - integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== - dependencies: - big-integer "^1.6.44" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -422,12 +464,12 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" buffer@^6.0.3: version "6.0.3" @@ -438,26 +480,22 @@ buffer@^6.0.3: ieee754 "^1.2.1" builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" + integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== dependencies: semver "^7.0.0" -bundle-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" - integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: - run-applescript "^5.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -517,12 +555,12 @@ color-name@~1.1.4: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== create-require@^1.1.0: version "1.1.1" @@ -536,7 +574,7 @@ cross-env@^7.0.3: dependencies: cross-spawn "^7.0.1" -cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.1, 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== @@ -550,12 +588,37 @@ crypto@^1.0.1: resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== -date-fns@^2.29.3: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== dependencies: - "@babel/runtime" "^7.21.0" + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +dayjs@^1.11.9: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== debug@^3.2.7: version "3.2.7" @@ -564,17 +627,10 @@ debug@^3.2.7: dependencies: ms "^2.1.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== - dependencies: - ms "2.1.2" - -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== +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: ms "2.1.2" @@ -584,52 +640,32 @@ decimal.js-light@^2.5.1: integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + 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== -default-browser-id@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" - integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - bplist-parser "^0.2.0" - untildify "^4.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" -default-browser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" - integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== - dependencies: - bundle-name "^3.0.0" - default-browser-id "^3.0.0" - execa "^7.1.1" - titleize "^3.0.0" - -define-lazy-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" - integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4, define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" -denque@^1.4.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== +denque@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== diff@^4.0.1: version "4.0.2" @@ -663,78 +699,119 @@ dotenv@^10.0.0: integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== dotenv@^16.0.3: - version "16.3.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" - integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -enhanced-resolve@^5.12.0: - version "5.14.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz#de684b6803724477a4af5d74ccae5de52c25f6b3" - integrity sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enhanced-resolve@^5.15.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" - integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: - array-buffer-byte-length "^1.0.0" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.0" - get-symbol-description "^1.0.0" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.10" + is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" + which-typed-array "^1.1.15" -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: +es-define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: - has "^1.0.3" + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -746,14 +823,14 @@ es-to-primitive@^1.2.1: is-symbol "^1.0.2" escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== 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= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^4.0.0: version "4.0.0" @@ -761,42 +838,42 @@ escape-string-regexp@^4.0.0: integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== eslint-config-prettier@^8.8.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== + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" + integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== eslint-config-standard@^17.0.0: version "17.1.0" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== -eslint-import-resolver-node@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" + is-core-module "^2.13.0" + resolve "^1.22.4" eslint-import-resolver-typescript@^3.5.4: - version "3.5.5" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz#0a9034ae7ed94b254a360fbea89187b60ea7456d" - integrity sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw== + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - get-tsconfig "^4.5.0" - globby "^13.1.3" - is-core-module "^2.11.0" + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" is-glob "^4.0.3" - synckit "^0.8.5" -eslint-module-utils@^2.7.4: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== +eslint-module-utils@^2.8.0, eslint-module-utils@^2.8.1: + version "2.8.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz#2ecad69d71e1fa81f17f7f24d5d3e46b168de663" + integrity sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg== dependencies: debug "^3.2.7" @@ -809,25 +886,27 @@ eslint-plugin-es@^4.1.0: regexpp "^3.0.0" eslint-plugin-import@^2.27.5: - version "2.27.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" - integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== + version "2.29.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.7.4" - has "^1.0.3" - is-core-module "^2.11.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.6" - resolve "^1.22.1" - semver "^6.3.0" - tsconfig-paths "^3.14.1" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" eslint-plugin-n@^15.7.0: version "15.7.0" @@ -851,9 +930,9 @@ eslint-plugin-prettier@^4.2.1: prettier-linter-helpers "^1.0.0" eslint-plugin-promise@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" - integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + version "6.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" + integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== eslint-plugin-security@^1.7.1: version "1.7.1" @@ -870,10 +949,10 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -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== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -902,32 +981,33 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" - integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.37.0: - version "8.42.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.42.0.tgz#7bebdc3a55f9ed7167251fe7259f75219cade291" - integrity sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A== + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.3" - "@eslint/js" "8.42.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.1" - espree "^9.5.2" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -937,7 +1017,6 @@ eslint@^8.37.0: globals "^13.19.0" graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" @@ -947,24 +1026,23 @@ eslint@^8.37.0: lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.5.2: - version "9.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" - integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" 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== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -981,59 +1059,29 @@ estraverse@^4.1.1: integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -execa@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" - integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - 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" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.11, fast-glob@^3.2.12, 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== +fast-glob@^3.2.9, fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -1049,12 +1097,12 @@ fast-json-stable-stringify@^2.0.0: 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== fastq@^1.6.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794" - integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -1065,10 +1113,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -1081,17 +1129,18 @@ find-up@^5.0.0: path-exists "^4.0.0" 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== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" - integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== for-each@^0.3.3: version "0.3.3" @@ -1100,27 +1149,35 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functions-have-names@^1.2.2, functions-have-names@^1.2.3: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -1137,42 +1194,30 @@ get-caller-file@^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-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" + es-errors "^1.3.0" + function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" -get-stream@^6.0.0, get-stream@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" -get-tsconfig@^4.5.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.6.0.tgz#e977690993a42f3e320e932427502a40f7af6d05" - integrity sha512-lgbo68hHTQnFddybKbbs/RDRJnJT5YyGy2kQzVwbq+g67X73i+5MVTval34QxGkOe9X5Ujf1UYpCaphLyltjEg== +get-tsconfig@^4.7.5: + version "4.8.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.0.tgz#125dc13a316f61650a12b20c97c11b8fd996fedd" + integrity sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw== dependencies: resolve-pkg-maps "^1.0.0" @@ -1190,42 +1235,44 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + 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== + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.1.0: - 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" - globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - define-properties "^1.1.3" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -1239,17 +1286,6 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^13.1.3: - version "13.1.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317" - integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g== - dependencies: - dir-glob "^3.0.1" - fast-glob "^3.2.11" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^4.0.0" - gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -1262,22 +1298,12 @@ graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -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== - graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-bigints@^1.0.2: +has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== @@ -1287,58 +1313,43 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.1, has-symbols@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" -has-symbols@^1.0.3: +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" + has-symbols "^1.0.3" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - -iconv-lite@^0.6.2: +iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -1350,17 +1361,12 @@ ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.1.1: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^5.2.0, ignore@^5.2.4: - 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.2.1: +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== @@ -1371,12 +1377,12 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -1386,23 +1392,22 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + es-errors "^1.3.0" + hasown "^2.0.0" side-channel "^1.0.4" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" + get-intrinsic "^1.2.1" is-bigint@^1.0.1: version "1.0.4" @@ -1419,22 +1424,31 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-callable@^1.1.3, is-callable@^1.2.7: +is-bun-module@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.1.0.tgz#a66b9830869437f6cdad440ba49ab6e4dc837269" + integrity sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA== + dependencies: + semver "^7.6.3" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-callable@^1.1.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.11.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - has "^1.0.3" + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" is-date-object@^1.0.1: version "1.0.5" @@ -1443,56 +1457,32 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-docker@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" - integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.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-inside-container@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" - integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== - dependencies: - is-docker "^3.0.0" - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: has-tostringtag "^1.0.0" @@ -1509,7 +1499,7 @@ is-path-inside@^3.0.3: is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= + integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== is-regex@^1.1.4: version "1.1.4" @@ -1519,22 +1509,12 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + call-bind "^1.0.7" is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" @@ -1550,16 +1530,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.14" is-weakref@^1.0.2: version "1.0.2" @@ -1568,22 +1544,29 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" js-yaml@^4.1.0: version "4.1.0" @@ -1592,6 +1575,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -1600,7 +1588,7 @@ json-schema-traverse@^0.4.1: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^1.0.2: version "1.0.2" @@ -1609,6 +1597,13 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1634,13 +1629,10 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -lru-cache@^4.1.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^6.0.0: version "6.0.0" @@ -1649,70 +1641,53 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - 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== micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.3" + picomatch "^2.3.1" -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-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.5, minimatch@^3.1.2: +minimatch@^3.0.5, minimatch@^3.1.1, 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" -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== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== 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" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + mkdirp@^2.1.3: version "2.1.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" @@ -1729,13 +1704,13 @@ ms@^2.1.1: integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== mysql2@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.0.tgz#600f5cc27e397dfb77b59eac93666434f88e8079" - integrity sha512-0t5Ivps5Tdy5YHk5NdKwQhe/4Qyn2pload+S+UooDBvsqngtzujG1BaTWBihQLfeKO3t3122/GtusBtmHEHqww== + version "2.3.3" + resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" + integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== dependencies: - denque "^1.4.1" + denque "^2.0.1" generate-function "^2.3.1" - iconv-lite "^0.6.2" + iconv-lite "^0.6.3" long "^4.0.0" lru-cache "^6.0.0" named-placeholders "^1.1.2" @@ -1762,11 +1737,11 @@ mz@^2.4.0: thenify-all "^1.0.0" named-placeholders@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.2.tgz#ceb1fbff50b6b33492b5cf214ccf5e39cef3d0e8" - integrity sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA== + version "1.1.3" + resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" + integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== dependencies: - lru-cache "^4.1.3" + lru-cache "^7.14.1" natural-compare-lite@^1.4.0: version "1.4.0" @@ -1776,103 +1751,79 @@ natural-compare-lite@^1.4.0: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.3: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== -object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== - -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" + call-bind "^1.0.5" + define-properties "^1.2.1" has-symbols "^1.0.3" object-keys "^1.1.1" -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.fromentries@^2.0.7: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.2: - 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" - -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -open@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" - integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== - dependencies: - default-browser "^4.0.0" - define-lazy-prop "^3.0.0" - is-inside-container "^1.0.0" - is-wsl "^2.2.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" p-limit@^3.0.2: version "3.1.0" @@ -1888,6 +1839,11 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -1920,37 +1876,40 @@ path-exists@^4.0.0: 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= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.0.0, path-key@^3.1.0: +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-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + 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== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== prelude-ls@^1.2.1: version "1.2.1" @@ -1974,15 +1933,10 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== queue-microtask@^1.2.2: version "1.2.3" @@ -2003,28 +1957,29 @@ readable-stream@2.3.7: util-deprecate "~1.0.1" reflect-metadata@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + version "0.1.14" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859" + integrity sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A== -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +reflect-metadata@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== regexp-tree@~0.1.1: version "0.1.27" resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== -regexp.prototype.flags@^1.4.3: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" regexpp@^3.0.0: version "3.2.0" @@ -2034,7 +1989,7 @@ regexpp@^3.0.0: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== resolve-from@^4.0.0: version "4.0.0" @@ -2046,12 +2001,12 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.22.1: - version "1.22.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== +resolve@^1.22.1, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.11.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -2067,13 +2022,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -run-applescript@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" - integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== - dependencies: - execa "^5.0.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2081,6 +2029,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + 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" @@ -2091,13 +2049,13 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" + call-bind "^1.0.6" + es-errors "^1.3.0" is-regex "^1.1.4" safe-regex@^2.1.1: @@ -2112,22 +2070,42 @@ safe-regex@^2.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -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@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.3.7, semver@^7.3.8: - version "7.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec" - integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw== - dependencies: - lru-cache "^6.0.0" +semver@^7.0.0, semver@^7.3.7, semver@^7.3.8, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= + integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" sha.js@^2.4.11: version "2.4.11" @@ -2150,49 +2128,36 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" -signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - sqlstring@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" - integrity sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A= + integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ== sqlstring@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.2.tgz#cdae7169389a1375b18e885f2e60b3e460809514" - integrity sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" + integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": 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== @@ -2201,32 +2166,51 @@ string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== +string-width@^4.1.0, string-width@^4.2.0, 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== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@~1.1.1: version "1.1.1" @@ -2235,36 +2219,33 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +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== @@ -2281,14 +2262,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" - integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== - dependencies: - "@pkgr/utils" "^2.3.1" - tslib "^2.5.0" - tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -2297,12 +2270,12 @@ tapable@^2.2.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= + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== dependencies: thenify ">= 3.1.0 < 4" @@ -2313,11 +2286,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -titleize@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" - integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2334,11 +2302,11 @@ ts-mysql-migrate@^1.0.2: mysql "^2.18.1" ts-node@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" - integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: - "@cspotcode/source-map-support" "0.6.1" + "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" @@ -2349,12 +2317,13 @@ ts-node@^10.2.1: create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^3.14.1: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.2" @@ -2367,9 +2336,9 @@ tslib@^1.8.1: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" - integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== tsutils@^3.21.0: version "3.21.0" @@ -2390,40 +2359,75 @@ type-fest@^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== -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typeorm@^0.3.16: - version "0.3.17" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.17.tgz#a73c121a52e4fbe419b596b244777be4e4b57949" - integrity sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig== + version "0.3.20" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab" + integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q== dependencies: "@sqltools/formatter" "^1.2.5" app-root-path "^3.1.0" buffer "^6.0.3" chalk "^4.1.2" cli-highlight "^2.1.11" - date-fns "^2.29.3" + dayjs "^1.11.9" debug "^4.3.4" dotenv "^16.0.3" - glob "^8.1.0" + glob "^10.3.10" mkdirp "^2.1.3" - reflect-metadata "^0.1.13" + reflect-metadata "^0.2.1" sha.js "^2.4.11" tslib "^2.5.0" uuid "^9.0.0" yargs "^17.6.2" typescript@^4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== unbox-primitive@^1.0.2: version "1.0.2" @@ -2435,10 +2439,10 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== uri-js@^4.2.2: version "4.4.1" @@ -2450,7 +2454,7 @@ uri-js@^4.2.2: util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== uuid@^8.3.2: version "8.3.2" @@ -2458,9 +2462,14 @@ uuid@^8.3.2: integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== 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== + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +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" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== which-boxed-primitive@^1.0.2: version "1.0.2" @@ -2473,17 +2482,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" + has-tostringtag "^1.0.2" which@^2.0.1: version "2.0.2" @@ -2492,10 +2500,19 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -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== +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^7.0.0: version "7.0.0" @@ -2506,21 +2523,25 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 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@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" From d269fb4799c2ac594952477daae83ddb4eb56587 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 21 Sep 2024 09:42:44 +0200 Subject: [PATCH 006/226] add dlt_users table analog to dlt_transactions --- .../0087-add_dlt_users_table/DltUser.ts | 33 ++++ .../entity/0087-add_dlt_users_table/User.ts | 181 ++++++++++++++++++ database/entity/DltUser.ts | 1 + database/entity/User.ts | 2 +- database/entity/index.ts | 2 + database/logging/DltUserLogging.view.ts | 23 +++ .../migrations/0087-add_dlt_users_table.ts | 19 ++ 7 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 database/entity/0087-add_dlt_users_table/DltUser.ts create mode 100644 database/entity/0087-add_dlt_users_table/User.ts create mode 100644 database/entity/DltUser.ts create mode 100644 database/logging/DltUserLogging.view.ts create mode 100644 database/migrations/0087-add_dlt_users_table.ts diff --git a/database/entity/0087-add_dlt_users_table/DltUser.ts b/database/entity/0087-add_dlt_users_table/DltUser.ts new file mode 100644 index 000000000..ca916e128 --- /dev/null +++ b/database/entity/0087-add_dlt_users_table/DltUser.ts @@ -0,0 +1,33 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' +import { User } from '../User' + +@Entity('dlt_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class DltUser extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) + userId: number + + @Column({ + name: 'message_id', + length: 64, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + messageId: string + + @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) + verified: boolean + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) + verifiedAt: Date | null + + @OneToOne(() => User, (user) => user.dltUser) + @JoinColumn({ name: 'user_id' }) + user?: User | null +} diff --git a/database/entity/0087-add_dlt_users_table/User.ts b/database/entity/0087-add_dlt_users_table/User.ts new file mode 100644 index 000000000..8d5466241 --- /dev/null +++ b/database/entity/0087-add_dlt_users_table/User.ts @@ -0,0 +1,181 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, + OneToOne, + Geometry, + ManyToOne, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { UserContact } from '../UserContact' +import { UserRole } from '../UserRole' +import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' +import { Community } from '../Community' +import { DltUser } from '../DltUser' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ type: 'bool', default: false }) + foreign: boolean + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'community_uuid', + type: 'char', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + communityUuid: string + + @ManyToOne(() => Community, (community) => community.users) + @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) + community: Community | null + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) + @JoinColumn({ name: 'email_id' }) + emailContact: UserContact + + @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) + emailId: number | null + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) + gmsPublishName: number + + @Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) + humhubPublishName: number + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ + name: 'password_encryption_type', + type: 'int', + unsigned: true, + nullable: false, + default: 0, + }) + passwordEncryptionType: number + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ type: 'bool', default: false }) + hideAmountGDD: boolean + + @Column({ type: 'bool', default: false }) + hideAmountGDT: boolean + + @OneToMany(() => UserRole, (userRole) => userRole.user) + @JoinColumn({ name: 'user_id' }) + userRoles: UserRole[] + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ name: 'gms_allowed', type: 'bool', default: true }) + gmsAllowed: boolean + + @Column({ + name: 'location', + type: 'geometry', + default: null, + nullable: true, + transformer: GeometryTransformer, + }) + location: Geometry | null + + @Column({ + name: 'gms_publish_location', + type: 'int', + unsigned: true, + nullable: false, + default: 2, + }) + gmsPublishLocation: number + + @Column({ name: 'gms_registered', type: 'bool', default: false }) + gmsRegistered: boolean + + @Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true }) + gmsRegisteredAt: Date | null + + @Column({ name: 'humhub_allowed', type: 'bool', default: false }) + humhubAllowed: boolean + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] + + @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) + @JoinColumn({ name: 'user_id' }) + userContacts?: UserContact[] + + @OneToOne(() => DltUser, (dlt) => dlt.userId) + @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) + dltUser?: DltUser | null +} diff --git a/database/entity/DltUser.ts b/database/entity/DltUser.ts new file mode 100644 index 000000000..29c835233 --- /dev/null +++ b/database/entity/DltUser.ts @@ -0,0 +1 @@ +export { DltUser } from './0087-add_dlt_users_table/DltUser' diff --git a/database/entity/User.ts b/database/entity/User.ts index 993d983ef..5267c24cc 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0084-introduce_humhub_registration/User' +export { User } from './0087-add_dlt_users_table/User' diff --git a/database/entity/index.ts b/database/entity/index.ts index 3352abdb4..a5a988490 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -13,6 +13,7 @@ import { Community } from './Community' import { FederatedCommunity } from './FederatedCommunity' import { UserRole } from './UserRole' import { DltTransaction } from './DltTransaction' +import { DltUser } from './DltUser' import { PendingTransaction } from './0071-add-pending_transactions-table/PendingTransaction' export const entities = [ @@ -21,6 +22,7 @@ export const entities = [ ContributionLink, ContributionMessage, DltTransaction, + DltUser, Event, FederatedCommunity, LoginElopageBuys, diff --git a/database/logging/DltUserLogging.view.ts b/database/logging/DltUserLogging.view.ts new file mode 100644 index 000000000..c98c3f351 --- /dev/null +++ b/database/logging/DltUserLogging.view.ts @@ -0,0 +1,23 @@ +import { DltUser } from '../entity/DltUser' +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class DltUserLoggingView extends AbstractLoggingView { + public constructor(private self: DltUser) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + messageId: this.self.messageId, + verified: this.self.verified, + createdAt: this.dateToString(this.self.createdAt), + verifiedAt: this.dateToString(this.self.verifiedAt), + } + } +} diff --git a/database/migrations/0087-add_dlt_users_table.ts b/database/migrations/0087-add_dlt_users_table.ts new file mode 100644 index 000000000..fdb310c67 --- /dev/null +++ b/database/migrations/0087-add_dlt_users_table.ts @@ -0,0 +1,19 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(` + CREATE TABLE dlt_users ( + id int unsigned NOT NULL AUTO_INCREMENT, + user_id int(10) unsigned NOT NULL, + message_id varchar(64) NULL DEFAULT NULL, + verified tinyint(4) NOT NULL DEFAULT 0, + created_at datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + verified_at datetime(3), + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(`DROP TABLE dlt_users;`) +} From 68cb7b368bcc30cc0af05c035fd53baf83d1ba49 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 21 Sep 2024 15:49:32 +0200 Subject: [PATCH 007/226] refactor dlt connector usage, reduce complexity --- .../apis/dltConnector/DltConnectorClient.ts | 16 +-- .../dltConnector/model/TransactionRecipe.ts | 3 +- .../graphql/resolver/ContributionResolver.ts | 9 +- .../resolver/TransactionLinkResolver.ts | 3 +- .../graphql/resolver/TransactionResolver.ts | 9 +- backend/src/graphql/resolver/UserResolver.ts | 9 +- .../util/sendTransactionsToDltConnector.ts | 81 -------------- backend/src/index.ts | 5 + .../sendTransactionsToDltConnector.test.ts | 0 .../tasks/sendTransactionsToDltConnector.ts | 101 ++++++++++++++++++ backend/src/util/InterruptiveSleep.ts | 31 ++++++ backend/src/util/InterruptiveSleepManager.ts | 67 ++++++++++++ 12 files changed, 230 insertions(+), 104 deletions(-) delete mode 100644 backend/src/graphql/resolver/util/sendTransactionsToDltConnector.ts rename backend/src/{graphql/resolver/util => tasks}/sendTransactionsToDltConnector.test.ts (100%) create mode 100644 backend/src/tasks/sendTransactionsToDltConnector.ts create mode 100644 backend/src/util/InterruptiveSleep.ts create mode 100644 backend/src/util/InterruptiveSleepManager.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 85e8bfb0a..4737d95bc 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -103,10 +103,12 @@ export class DltConnectorClient { * transmit transaction via dlt-connector to iota * and update dltTransactionId of transaction in db with iota message id */ - public async transmitTransaction(transaction: DbTransaction): Promise { + public async transmitTransaction( + transaction: DbTransaction, + ): Promise { // we don't need the receive transactions, there contain basically the same data as the send transactions if ((transaction.typeId as TransactionTypeId) === TransactionTypeId.RECEIVE) { - return true + return } const typeString = getTransactionTypeString(transaction.typeId) // no negative values in dlt connector, gradido concept don't use negative values so the code don't use it too @@ -132,17 +134,15 @@ export class DltConnectorClient { // TODO: add account nr for user after they have also more than one account in backend logger.debug('transmit transaction to dlt connector', params) const { - data: { - sendTransaction: { error, succeed }, - }, + data: { sendTransaction: result }, } = await this.client.rawRequest<{ sendTransaction: TransactionResult }>( sendTransaction, params, ) - if (error) { - throw new Error(error.message) + if (result.error) { + throw new Error(result.error.message) } - return succeed + return result } catch (e) { throw new LogError('Error send sending transaction to dlt-connector: ', e) } diff --git a/backend/src/apis/dltConnector/model/TransactionRecipe.ts b/backend/src/apis/dltConnector/model/TransactionRecipe.ts index edd7deadb..504ff2044 100644 --- a/backend/src/apis/dltConnector/model/TransactionRecipe.ts +++ b/backend/src/apis/dltConnector/model/TransactionRecipe.ts @@ -1,8 +1,7 @@ import { TransactionType } from '@dltConnector/enum/TransactionType' export interface TransactionRecipe { - id: number createdAt: string type: TransactionType - topic: string + messageIdHex: string } diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 5684835e4..145d70a3f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -43,6 +43,10 @@ import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { calculateDecay } from '@/util/decay' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' @@ -50,7 +54,6 @@ import { findContribution } from './util/contributions' import { getUserCreation, validateContribution, getOpenCreations } from './util/creations' import { findContributions } from './util/findContributions' import { getLastTransaction } from './util/getLastTransaction' -import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector' @Resolver() export class ContributionResolver { @@ -473,8 +476,8 @@ export class ContributionResolver { await queryRunner.commitTransaction() - // trigger to send transaction via dlt-connector - void sendTransactionsToDltConnector() + // notify dlt-connector loop for new work + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) logger.info('creation commited successfuly.') void sendContributionConfirmedEmail({ diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 63134a9a8..0ef7f0586 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -38,10 +38,11 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' +import { sendTransactionsToDltConnector } from '../../tasks/sendTransactionsToDltConnector' + import { executeTransaction } from './TransactionResolver' import { getUserCreation, validateContribution } from './util/creations' import { getLastTransaction } from './util/getLastTransaction' -import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector' import { transactionLinkList } from './util/transactionLinkList' // TODO: do not export, test it inside the resolver diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 1889e3be0..1d652adfe 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -32,6 +32,10 @@ import { Context, getUser } from '@/server/context' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { communityUser } from '@/util/communityUser' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' @@ -47,7 +51,6 @@ import { processXComCommittingSendCoins, processXComPendingSendCoins, } from './util/processXComSendCoins' -import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector' import { storeForeignUser } from './util/storeForeignUser' import { transactionLinkSummary } from './util/transactionLinkSummary' @@ -177,8 +180,8 @@ export const executeTransaction = async ( transactionReceive.amount, ) - // trigger to send transaction via dlt-connector - void sendTransactionsToDltConnector() + // notify dlt-connector loop for new work + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Transaction was not successful', e) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 93c63e659..6ddd15705 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -30,7 +30,6 @@ import { GmsUserAuthenticationResult } from '@model/GmsUserAuthenticationResult' import { User } from '@model/User' import { UserAdmin, SearchUsersResult } from '@model/UserAdmin' -import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' import { updateGmsUser } from '@/apis/gms/GmsClient' import { GmsUser } from '@/apis/gms/model/GmsUser' import { HumHubClient } from '@/apis/humhub/HumHubClient' @@ -67,6 +66,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' +import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/util/InterruptiveSleepManager' import { getTimeDurationObject, printTimeDuration } from '@/util/time' import random from 'random-bigint' @@ -385,11 +385,8 @@ export class UserResolver { } logger.info('createUser() successful...') - const dltConnector = DltConnectorClient.getInstance() - if (dltConnector) { - const r = await dltConnector.registerAddress(dbUser) - console.log('result from dlt', r) - } + // notify dlt-connector loop for new work + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) if (redeemCode) { eventRegisterRedeem.affectedUser = dbUser diff --git a/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.ts b/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.ts deleted file mode 100644 index 733c12594..000000000 --- a/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { IsNull } from '@dbTools/typeorm' -import { DltTransaction } from '@entity/DltTransaction' -import { Transaction } from '@entity/Transaction' - -import { DltConnectorClient } from '@dltConnector/DltConnectorClient' - -import { backendLogger as logger } from '@/server/logger' -import { Monitor, MonitorNames } from '@/util/Monitor' - -export async function sendTransactionsToDltConnector(): Promise { - logger.info('sendTransactionsToDltConnector...') - // check if this logic is still occupied, no concurrecy allowed - if (!Monitor.isLocked(MonitorNames.SEND_DLT_TRANSACTIONS)) { - // mark this block for occuption to prevent concurrency - Monitor.lockIt(MonitorNames.SEND_DLT_TRANSACTIONS) - - try { - await createDltTransactions() - const dltConnector = DltConnectorClient.getInstance() - if (dltConnector) { - logger.debug('with sending to DltConnector...') - const dltTransactions = await DltTransaction.find({ - where: { messageId: IsNull() }, - relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - for (const dltTx of dltTransactions) { - if (!dltTx.transaction) { - continue - } - try { - const result = await dltConnector.transmitTransaction(dltTx.transaction) - // message id isn't known at this point of time, because transaction will not direct sended to iota, - // it will first go to db and then sended, if no transaction is in db before - if (result) { - dltTx.messageId = 'sended' - await DltTransaction.save(dltTx) - logger.info('store messageId=%s in dltTx=%d', dltTx.messageId, dltTx.id) - } - } catch (e) { - logger.error( - `error while sending to dlt-connector or writing messageId of dltTx=${dltTx.id}`, - e, - ) - } - } - } else { - logger.info('sending to DltConnector currently not configured...') - } - } catch (e) { - logger.error('error on sending transactions to dlt-connector.', e) - } finally { - // releae Monitor occupation - Monitor.releaseIt(MonitorNames.SEND_DLT_TRANSACTIONS) - } - } else { - logger.info('sendTransactionsToDltConnector currently locked by monitor...') - } -} - -async function createDltTransactions(): Promise { - const dltqb = DltTransaction.createQueryBuilder().select('transactions_id') - const newTransactions: Transaction[] = await Transaction.createQueryBuilder() - .select('id') - .addSelect('balance_date') - .where('id NOT IN (' + dltqb.getSql() + ')') - // eslint-disable-next-line camelcase - .orderBy({ balance_date: 'ASC', id: 'ASC' }) - .getRawMany() - - const dltTxArray: DltTransaction[] = [] - let idx = 0 - while (newTransactions.length > dltTxArray.length) { - // timing problems with for(let idx = 0; idx < newTransactions.length; idx++) { - const dltTx = DltTransaction.create() - dltTx.transactionId = newTransactions[idx++].id - await DltTransaction.save(dltTx) - dltTxArray.push(dltTx) - } -} diff --git a/backend/src/index.ts b/backend/src/index.ts index 86f78326d..5cb3574e4 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,6 +1,7 @@ import { CONFIG } from './config' import { startValidateCommunities } from './federation/validateCommunities' import { createServer } from './server/createServer' +import { sendTransactionsToDltConnector } from './tasks/sendTransactionsToDltConnector' async function main() { const { app } = await createServer() @@ -13,6 +14,10 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) } }) + // task is running the whole time for transmitting transaction via dlt-connector to iota + // can be notified with InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) + // that a new transaction or user was stored in db + void sendTransactionsToDltConnector() void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } diff --git a/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts b/backend/src/tasks/sendTransactionsToDltConnector.test.ts similarity index 100% rename from backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts rename to backend/src/tasks/sendTransactionsToDltConnector.test.ts diff --git a/backend/src/tasks/sendTransactionsToDltConnector.ts b/backend/src/tasks/sendTransactionsToDltConnector.ts new file mode 100644 index 000000000..26535e082 --- /dev/null +++ b/backend/src/tasks/sendTransactionsToDltConnector.ts @@ -0,0 +1,101 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { DltUser } from '@entity/DltUser' +import { Transaction } from '@entity/Transaction' +import { User } from '@entity/User' + +import { DltConnectorClient } from '@dltConnector/DltConnectorClient' + +import { backendLogger as logger } from '@/server/logger' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' + +let running = true + +export const stopSendTransactionsToDltConnector = (): void => { + running = false +} + +export async function sendTransactionsToDltConnector(): Promise { + const dltConnector = DltConnectorClient.getInstance() + if (!dltConnector) { + logger.info('sending to DltConnector currently not configured...') + running = false + return + } + logger.info('start sendTransactionsToDltConnector task') + + // eslint-disable-next-line no-unmodified-loop-condition + while (running) { + try { + // loop while work could be found + while (true) { + const pendingTransaction = await findNextPendingTransaction() + if (pendingTransaction instanceof User) { + const result = await dltConnector.registerAddress(pendingTransaction) + if (result?.succeed && result.recipe) { + const dltUser = DltUser.create() + dltUser.userId = pendingTransaction.id + dltUser.messageId = result.recipe.messageIdHex + // wait until saved, necessary before next call to findNextPendingTransaction + await DltUser.save(dltUser) + logger.info('store dltUser: messageId=%s in dltTx=%d', dltUser.messageId, dltUser.id) + } + } else if (pendingTransaction instanceof Transaction) { + const result = await dltConnector.transmitTransaction(pendingTransaction) + if (result?.succeed && result.recipe) { + const dltTransaction = DltTransaction.create() + dltTransaction.transactionId = pendingTransaction.id + dltTransaction.messageId = result.recipe.messageIdHex + // wait until saved, necessary before next call to findNextPendingTransaction + await DltTransaction.save(dltTransaction) + logger.info( + 'store dltTransaction: messageId=%s in dltTx=%d', + dltTransaction.messageId, + dltTransaction.id, + ) + } + } else { + // nothing to do, break inner loop and sleep until new work has arrived + break + } + } + await InterruptiveSleepManager.getInstance().sleep( + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, + 1000, + ) + } catch (e) { + logger.error(`error while sending to dlt-connector or writing messageId`, e) + } + } +} + +async function findNextPendingTransaction(): Promise { + const lastTransactionPromise: Promise = Transaction.createQueryBuilder() + .select() + .leftJoin(DltTransaction, 'dltTransaction', 'transaction.id = dltTransaction.transactionId') + .where('dltTransaction.transactionId IS NULL') + // eslint-disable-next-line camelcase + .orderBy({ balance_date: 'ASC', id: 'ASC' }) + .limit(1) + .getRawOne() + + const lastUserPromise: Promise = User.createQueryBuilder() + .leftJoin(DltUser, 'dltUser', 'user.id = dltUser.userId') + .where('dltUser.userId IS NULL') + // eslint-disable-next-line camelcase + .orderBy({ created_at: 'ASC', id: 'ASC' }) + .limit(1) + .getRawOne() + + const results = await Promise.all([lastTransactionPromise, lastUserPromise]) + if (results[0] && results[1]) { + return results[0].balanceDate < results[1].createdAt ? results[0] : results[1] + } else if (results[0]) { + return results[0] + } else if (results[1]) { + return results[1] + } + return null +} diff --git a/backend/src/util/InterruptiveSleep.ts b/backend/src/util/InterruptiveSleep.ts new file mode 100644 index 000000000..c21e57db9 --- /dev/null +++ b/backend/src/util/InterruptiveSleep.ts @@ -0,0 +1,31 @@ +/** + * Sleep, that can be interrupted + * call sleep only for msSteps and than check if interrupt was called + */ +export class InterruptiveSleep { + private interruptSleep = false + private msSteps = 10 + + constructor(msSteps: number) { + this.msSteps = msSteps + } + + public interrupt(): void { + this.interruptSleep = true + } + + private static _sleep(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms) + }) + } + + public async sleep(ms: number): Promise { + let waited = 0 + this.interruptSleep = false + while (waited < ms && !this.interruptSleep) { + await InterruptiveSleep._sleep(this.msSteps) + waited += this.msSteps + } + } +} diff --git a/backend/src/util/InterruptiveSleepManager.ts b/backend/src/util/InterruptiveSleepManager.ts new file mode 100644 index 000000000..246269623 --- /dev/null +++ b/backend/src/util/InterruptiveSleepManager.ts @@ -0,0 +1,67 @@ +import { LogError } from '@/server/LogError' + +import { InterruptiveSleep } from './InterruptiveSleep' + +// Source: https://refactoring.guru/design-patterns/singleton/typescript/example +// and ../federation/client/FederationClientFactory.ts +/** + * Managing Instances of interruptive sleep it is inspired from conditions from c++ multithreading + * It is used for separate worker threads which will go to sleep after they haven't anything todo left, + * but with this Manager and InterruptiveSleep Object it sleeps only stepSize and check if something interrupted his sleep, + * so he can check for new work + */ +export const TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY = 'transmitToIota' + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class InterruptiveSleepManager { + // eslint-disable-next-line no-use-before-define + private static instance: InterruptiveSleepManager + private interruptiveSleep: Map = new Map() + private stepSizeMilliseconds = 10 + + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor() {} + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(): InterruptiveSleepManager { + if (!InterruptiveSleepManager.instance) { + InterruptiveSleepManager.instance = new InterruptiveSleepManager() + } + return InterruptiveSleepManager.instance + } + + /** + * only for new created InterruptiveSleepManager Entries! + * @param step size in ms in which new! InterruptiveSleepManager check if they where triggered + */ + public setStepSize(ms: number) { + this.stepSizeMilliseconds = ms + } + + public interrupt(key: string): void { + const interruptiveSleep = this.interruptiveSleep.get(key) + if (interruptiveSleep) { + interruptiveSleep.interrupt() + } + } + + public sleep(key: string, ms: number): Promise { + if (!this.interruptiveSleep.has(key)) { + this.interruptiveSleep.set(key, new InterruptiveSleep(this.stepSizeMilliseconds)) + } + const interruptiveSleep = this.interruptiveSleep.get(key) + if (!interruptiveSleep) { + throw new LogError('map entry not exist after setting it') + } + return interruptiveSleep.sleep(ms) + } +} From 2727b6ebe99e31993f686a903a18afc8282c538c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sun, 22 Sep 2024 16:35:15 +0200 Subject: [PATCH 008/226] add new send to iota interaction --- dlt-connector/.env.dist | 4 +- dlt-connector/.env.template | 4 +- dlt-connector/package.json | 1 + dlt-connector/src/client/GradidoNode.ts | 124 ++++++++++++++++++ dlt-connector/src/config/index.ts | 7 +- .../src/data/Community.repository.ts | 10 +- .../src/graphql/model/TransactionRecipe.ts | 31 ++--- .../src/graphql/resolver/CommunityResolver.ts | 4 +- dlt-connector/src/index.ts | 25 ++-- .../community/AddCommunity.context.ts | 4 +- .../CreateTransactionRecipe.context.test.ts | 6 +- .../AbstractKeyPair.role.ts | 5 + .../AbstractRemoteKeyPair.role.ts | 5 + .../keyPairCalculation/AccountKeyPair.role.ts | 13 ++ .../ForeignCommunityKeyPair.role.ts | 31 +++++ .../HomeCommunityKeyPair.role.ts | 22 ++++ .../KeyPairCalculation.context.ts | 56 ++++++++ .../RemoteAccountKeyPair.role.ts | 35 +++++ .../keyPairCalculation/UserKeyPair.role.ts | 28 ++++ .../sendToIota/AbstractTransaction.role.ts | 7 + .../CommunityRootTransaction.role.ts | 47 +++++++ .../sendToIota/CreationTransaction.role.ts | 39 ++++++ .../RegisterAddressTransaction.role.ts | 40 ++++++ .../sendToIota/SendToIota.context.ts | 116 ++++++++++++++++ .../sendToIota/TransferTransaction.role.ts | 44 +++++++ .../src/manager/KeyPairCacheManager.ts | 66 ++++++++++ dlt-connector/src/utils/derivationHelper.ts | 2 + dlt-connector/src/utils/typeConverter.test.ts | 4 +- dlt-connector/src/utils/typeConverter.ts | 30 ++++- dlt-connector/test/seeding/Community.seed.ts | 4 +- dlt-connector/yarn.lock | 33 +++-- 31 files changed, 779 insertions(+), 68 deletions(-) create mode 100644 dlt-connector/src/client/GradidoNode.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts create mode 100644 dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts create mode 100644 dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts create mode 100644 dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts create mode 100644 dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts create mode 100644 dlt-connector/src/interactions/sendToIota/SendToIota.context.ts create mode 100644 dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts create mode 100644 dlt-connector/src/manager/KeyPairCacheManager.ts diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 164e23036..8ad78348d 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -21,10 +21,12 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log # DLT-Connector DLT_CONNECTOR_PORT=6010 +# Gradido Node Server URL +NODE_SERVER_URL=http://localhost:8340 + # Gradido Blockchain GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=21ffbbc616fe GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=a51ef8ac7ef1abf162fb7a65261acd7a -GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD=YourPassword # Route to Backend BACKEND_SERVER_URL=http://localhost:4000 diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index d7d46dad7..15c2ae5a9 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -19,10 +19,12 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log # DLT-Connector DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT +# Gradido Node Server URL +NODE_SERVER_URL=$NODE_SERVER_URL + # Gradido Blockchain GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY -GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD=$GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD # Route to Backend BACKEND_SERVER_URL=http://localhost:4000 \ No newline at end of file diff --git a/dlt-connector/package.json b/dlt-connector/package.json index cf29417f5..ca889b833 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -33,6 +33,7 @@ "graphql-scalars": "^1.22.2", "helmet": "^7.1.0", "jose": "^5.2.2", + "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.7.1", "nodemon": "^2.0.20", "reflect-metadata": "^0.1.13", diff --git a/dlt-connector/src/client/GradidoNode.ts b/dlt-connector/src/client/GradidoNode.ts new file mode 100644 index 000000000..92a211768 --- /dev/null +++ b/dlt-connector/src/client/GradidoNode.ts @@ -0,0 +1,124 @@ +/* eslint-disable camelcase */ +import { AddressType, ConfirmedTransaction, stringToAddressType } from 'gradido-blockchain-js' +import JsonRpcClient from 'jsonrpc-ts-client' +import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' + +import { CONFIG } from '@/config' +import { logger } from '@/logging/logger' +import { LogError } from '@/server/LogError' +import { confirmedTransactionFromBase64, getEnumValue } from '@/utils/typeConverter' + +const client = new JsonRpcClient({ + url: CONFIG.NODE_SERVER_URL, +}) +/* +enum JsonRPCErrorCodes { + NONE = 0, + GRADIDO_NODE_ERROR = -10000, + UNKNOWN_GROUP = -10001, + NOT_IMPLEMENTED = -10002, + TRANSACTION_NOT_FOUND = -10003, + // default errors from json rpc standard: https://www.jsonrpc.org/specification + // -32700 Parse error Invalid JSON was received by the server. + PARSE_ERROR = -32700, + // -32600 Invalid Request The JSON sent is not a valid Request object. + INVALID_REQUEST = -32600, + // -32601 Method not found The method does not exist / is not available. + METHODE_NOT_FOUND = -32601, + // -32602 Invalid params Invalid method parameter(s). + INVALID_PARAMS = -32602, + // -32603 Internal error Internal JSON - RPC error. + INTERNAL_ERROR = -32603, + // -32000 to -32099 Server error Reserved for implementation-defined server-errors. +} +*/ + +interface ConfirmedTransactionList { + transactions: string[] + timeUsed: string +} + +interface ConfirmedTransactionResponse { + transaction: string + timeUsed: string +} + +interface AddressTypeResult { + addressType: string +} + +function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { + if (response.isSuccess()) { + return onSuccess(response.result) + } else if (response.isError()) { + throw new LogError('error by json rpc request to gradido node server', response.error) + } + throw new LogError('no success and no error', response) +} + +async function getTransactions( + fromTransactionId: number, + maxResultCount: number, + iotaTopic: string, +): Promise { + const parameter = { + format: 'base64', + fromTransactionId, + maxResultCount, + communityId: iotaTopic, + } + logger.info('call getTransactions on Node Server via jsonrpc 2.0 with ', parameter) + const response = await client.exec('getTransactions', parameter) // sends payload {jsonrpc: '2.0', params: ...} + return resolveResponse(response, (result: ConfirmedTransactionList) => { + logger.debug('GradidoNode used time', result.timeUsed) + return result.transactions.map((transactionBase64) => + confirmedTransactionFromBase64(transactionBase64), + ) + }) +} + +async function getTransaction( + transactionId: number | Buffer, + iotaTopic: string, +): Promise { + logger.info('call gettransaction on Node Server via jsonrpc 2.0') + const response = await client.exec('gettransaction', { + format: 'base64', + communityId: iotaTopic, + transactionId: typeof transactionId === 'number' ? transactionId : undefined, + iotaMessageId: transactionId instanceof Buffer ? transactionId.toString('hex') : undefined, + }) + return resolveResponse(response, (result: ConfirmedTransactionResponse) => { + logger.debug('GradidoNode used time', result.timeUsed) + return result.transaction && result.transaction !== '' + ? confirmedTransactionFromBase64(result.transaction) + : undefined + }) +} + +async function getLastTransaction(iotaTopic: string): Promise { + logger.info('call getlasttransaction on Node Server via jsonrpc 2.0') + const response = await client.exec('getlasttransaction', { + format: 'base64', + communityId: iotaTopic, + }) + return resolveResponse(response, (result: ConfirmedTransactionResponse) => { + logger.debug('GradidoNode used time', result.timeUsed) + return result.transaction && result.transaction !== '' + ? confirmedTransactionFromBase64(result.transaction) + : undefined + }) +} + +async function getAddressType(pubkey: Buffer, iotaTopic: string): Promise { + logger.info('call getaddresstype on Node Server via jsonrpc 2.0') + const response = await client.exec('getaddresstype', { + pubkey: pubkey.toString('hex'), + communityId: iotaTopic, + }) + return resolveResponse(response, (result: AddressTypeResult) => + stringToAddressType(result.addressType), + ) +} + +export { getTransaction, getLastTransaction, getTransactions, getAddressType } diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index f2f01cd8d..ff50eb3fe 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -39,13 +39,15 @@ const dltConnector = { DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT ?? 6010, } +const nodeServer = { + NODE_SERVER_URL: process.env.NODE_SERVER_URL ?? 'http://localhost:8340', +} + const gradidoBlockchain = { GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: process.env.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET ?? 'invalid', GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: process.env.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY ?? 'invalid', - GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD: - process.env.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD, } const backendServer = { @@ -70,6 +72,7 @@ export const CONFIG = { ...database, ...iota, ...dltConnector, + ...nodeServer, ...gradidoBlockchain, ...backendServer, } diff --git a/dlt-connector/src/data/Community.repository.ts b/dlt-connector/src/data/Community.repository.ts index a9fdf4e09..eb52fb38c 100644 --- a/dlt-connector/src/data/Community.repository.ts +++ b/dlt-connector/src/data/Community.repository.ts @@ -8,7 +8,7 @@ import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { TransactionError } from '@/graphql/model/TransactionError' import { LogError } from '@/server/LogError' import { getDataSource } from '@/typeorm/DataSource' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' +import { uuid4ToHash } from '@/utils/typeConverter' import { KeyPair } from './KeyPair' @@ -17,7 +17,7 @@ export const CommunityRepository = getDataSource() .extend({ async isExist(community: CommunityDraft | string): Promise { const iotaTopic = - community instanceof CommunityDraft ? iotaTopicFromCommunityUUID(community.uuid) : community + community instanceof CommunityDraft ? uuid4ToHash(community.uuid) : community const result = await this.find({ where: { iotaTopic }, }) @@ -27,7 +27,7 @@ export const CommunityRepository = getDataSource() async findByCommunityArg({ uuid, foreign, confirmed }: CommunityArg): Promise { return await this.find({ where: { - ...(uuid && { iotaTopic: iotaTopicFromCommunityUUID(uuid) }), + ...(uuid && { iotaTopic: uuid4ToHash(uuid) }), ...(foreign && { foreign }), ...(confirmed && { confirmedAt: Not(IsNull()) }), }, @@ -35,7 +35,7 @@ export const CommunityRepository = getDataSource() }, async findByCommunityUuid(communityUuid: string): Promise { - return await this.findOneBy({ iotaTopic: iotaTopicFromCommunityUUID(communityUuid) }) + return await this.findOneBy({ iotaTopic: uuid4ToHash(communityUuid) }) }, async findByIotaTopic(iotaTopic: string): Promise { @@ -54,7 +54,7 @@ export const CommunityRepository = getDataSource() } return ( (await this.findOneBy({ - iotaTopic: iotaTopicFromCommunityUUID(identifier.communityUuid), + iotaTopic: uuid4ToHash(identifier.communityUuid), })) ?? undefined ) }, diff --git a/dlt-connector/src/graphql/model/TransactionRecipe.ts b/dlt-connector/src/graphql/model/TransactionRecipe.ts index 78fa7fc31..eae7f1a6f 100644 --- a/dlt-connector/src/graphql/model/TransactionRecipe.ts +++ b/dlt-connector/src/graphql/model/TransactionRecipe.ts @@ -1,26 +1,20 @@ -import { Transaction } from '@entity/Transaction' -import { Field, Int, ObjectType } from 'type-graphql' +import { GradidoTransaction, MemoryBlock, transactionTypeToString } from 'gradido-blockchain-js' +import { Field, ObjectType } from 'type-graphql' -import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' import { LogError } from '@/server/LogError' -import { getEnumValue } from '@/utils/typeConverter' @ObjectType() export class TransactionRecipe { - public constructor({ id, createdAt, type, community, signature }: Transaction) { - const transactionType = getEnumValue(TransactionType, type) - if (!transactionType) { - throw new LogError('invalid transaction, type is missing') + public constructor(transaction: GradidoTransaction, messageId: MemoryBlock) { + const body = transaction.getTransactionBody() + if (!body) { + throw new LogError('invalid gradido transaction, cannot geht valid TransactionBody') } - this.id = id - this.createdAt = createdAt.toString() - this.type = transactionType.toString() - this.topic = community.iotaTopic - this.signatureHex = signature.toString('hex') - } - @Field(() => Int) - id: number + this.createdAt = body.getCreatedAt().getDate().toString() + this.type = transactionTypeToString(body?.getTransactionType()) + this.messageIdHex = messageId.convertToHex() + } @Field(() => String) createdAt: string @@ -29,8 +23,5 @@ export class TransactionRecipe { type: string @Field(() => String) - topic: string - - @Field(() => String) - signatureHex: string + messageIdHex: string } diff --git a/dlt-connector/src/graphql/resolver/CommunityResolver.ts b/dlt-connector/src/graphql/resolver/CommunityResolver.ts index dd9db2b23..848dd0733 100644 --- a/dlt-connector/src/graphql/resolver/CommunityResolver.ts +++ b/dlt-connector/src/graphql/resolver/CommunityResolver.ts @@ -10,7 +10,7 @@ import { CommunityRepository } from '@/data/Community.repository' import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' +import { uuid4ToHash } from '@/utils/typeConverter' @Resolver() export class CommunityResolver { @@ -46,7 +46,7 @@ export class CommunityResolver { communityDraft: CommunityDraft, ): Promise { logger.info('addCommunity', communityDraft) - const topic = iotaTopicFromCommunityUUID(communityDraft.uuid) + const topic = uuid4ToHash(communityDraft.uuid) // check if community was already written to db if (await CommunityRepository.isExist(topic)) { return new TransactionResult( diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 8d140faf3..b61157dfb 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -6,10 +6,10 @@ import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { CONFIG } from '@/config' import { BackendClient } from './client/BackendClient' -import { CommunityRepository } from './data/Community.repository' import { CommunityDraft } from './graphql/input/CommunityDraft' import { AddCommunityContext } from './interactions/backendToDb/community/AddCommunity.context' import { logger } from './logging/logger' +import { KeyPairCacheManager } from './manager/KeyPairCacheManager' import createServer from './server/createServer' import { LogError } from './server/LogError' import { stopTransmitToIota, transmitToIota } from './tasks/transmitToIota' @@ -61,20 +61,17 @@ async function main() { const { app } = await createServer() // ask backend for home community if we haven't one - try { - await CommunityRepository.loadHomeCommunityKeyPair() - } catch (e) { - const backend = BackendClient.getInstance() - if (!backend) { - throw new LogError('cannot create backend client') - } - // wait for backend server to be ready - await waitForServer(backend, 2500, 10) - - const communityDraft = await backend.getHomeCommunityDraft() - const addCommunityContext = new AddCommunityContext(communityDraft) - await addCommunityContext.run() + const backend = BackendClient.getInstance() + if (!backend) { + throw new LogError('cannot create backend client') } + // wait for backend server to be ready + await waitForServer(backend, 2500, 10) + + const communityDraft = await backend.getHomeCommunityDraft() + KeyPairCacheManager.getInstance().setHomeCommunityUUID(communityDraft.uuid) + const addCommunityContext = new AddCommunityContext(communityDraft) + await addCommunityContext.run() // loop run all the time, check for new transaction for sending to iota void transmitToIota() diff --git a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts b/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts index bc8f90c32..16bfd8513 100644 --- a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts +++ b/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts @@ -1,5 +1,5 @@ import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' +import { uuid4ToHash } from '@/utils/typeConverter' import { CommunityRole } from './Community.role' import { ForeignCommunityRole } from './ForeignCommunity.role' @@ -15,7 +15,7 @@ export class AddCommunityContext { private iotaTopic: string public constructor(private communityDraft: CommunityDraft, iotaTopic?: string) { if (!iotaTopic) { - this.iotaTopic = iotaTopicFromCommunityUUID(this.communityDraft.uuid) + this.iotaTopic = uuid4ToHash(this.communityDraft.uuid) } else { this.iotaTopic = iotaTopic } diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts index a38d9952f..6671e6e78 100644 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts +++ b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts @@ -22,7 +22,7 @@ import { AccountType } from '@/graphql/enum/AccountType' import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' +import { uuid4ToHash } from '@/utils/typeConverter' import { CreateTransactionRecipeContext } from './CreateTransactionRecipe.context' @@ -50,8 +50,8 @@ let secondUser: UserSet let foreignUser: UserSet let homeCommunity: Community -const topic = iotaTopicFromCommunityUUID(homeCommunityUuid) -const foreignTopic = iotaTopicFromCommunityUUID(foreignCommunityUuid) +const topic = uuid4ToHash(homeCommunityUuid) +const foreignTopic = uuid4ToHash(foreignCommunityUuid) describe('interactions/backendToDb/transaction/Create Transaction Recipe Context Test', () => { beforeAll(async () => { diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts new file mode 100644 index 000000000..cd17a3832 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts @@ -0,0 +1,5 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +export abstract class AbstractKeyPairRole { + public abstract generateKeyPair(): KeyPairEd25519 +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts new file mode 100644 index 000000000..1450d9cdb --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts @@ -0,0 +1,5 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +export abstract class AbstractRemoteKeyPairRole { + public abstract retrieveKeyPair(): Promise +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts new file mode 100644 index 000000000..517d33ae1 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts @@ -0,0 +1,13 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { AbstractKeyPairRole } from './AbstractKeyPair.role' + +export class AccountKeyPairRole extends AbstractKeyPairRole { + public constructor(private accountNr: number, private userKeyPair: KeyPairEd25519) { + super() + } + + public generateKeyPair(): KeyPairEd25519 { + return this.userKeyPair.deriveChild(this.accountNr) + } +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts new file mode 100644 index 000000000..68dd65a21 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -0,0 +1,31 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { getTransaction } from '@/client/GradidoNode' +import { LogError } from '@/server/LogError' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' + +export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { + public constructor(private communityUuid: string) { + super() + } + + public async retrieveKeyPair(): Promise { + const firstTransaction = await getTransaction(1, uuid4ToHash(this.communityUuid).convertToHex()) + if (!firstTransaction) { + throw new LogError( + "GradidoNode Server don't know this community with uuid " + this.communityUuid, + ) + } + const transactionBody = firstTransaction.getGradidoTransaction()?.getTransactionBody() + if (!transactionBody || !transactionBody.isCommunityRoot()) { + throw new LogError('get invalid confirmed transaction from gradido node') + } + const communityRoot = transactionBody.getCommunityRoot() + if (!communityRoot) { + throw new LogError('invalid confirmed transaction') + } + return new KeyPairEd25519(communityRoot.getPubkey()) + } +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts new file mode 100644 index 000000000..b888351cd --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts @@ -0,0 +1,22 @@ +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' + +import { CONFIG } from '@/config' +import { LogError } from '@/server/LogError' + +import { AbstractKeyPairRole } from './AbstractKeyPair.role' + +export class HomeCommunityKeyPairRole extends AbstractKeyPairRole { + public generateKeyPair(): KeyPairEd25519 { + if (!CONFIG.IOTA_HOME_COMMUNITY_SEED) { + throw new LogError( + 'IOTA_HOME_COMMUNITY_SEED is missing either in config or as environment variable', + ) + } + const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) + const keyPair = KeyPairEd25519.create(seed) + if (!keyPair) { + throw new LogError("couldn't create keyPair from IOTA_HOME_COMMUNITY_SEED") + } + return keyPair + } +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts new file mode 100644 index 000000000..8e6466df5 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -0,0 +1,56 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' + +import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' +import { AccountKeyPairRole } from './AccountKeyPair.role' +import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' +import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' +import { RemoteAccountKeyPairRole } from './RemoteAccountKeyPair.role' +import { UserKeyPairRole } from './UserKeyPair.role' + +/** + * @DCI-Context + * Context for calculating key pair for signing transactions + */ +export async function KeyPairCalculation(input: UserIdentifier | string): Promise { + const cache = KeyPairCacheManager.getInstance() + const keyPair = cache.findKeyPair(input) + if (keyPair) { + return keyPair + } + let communityUUID: string + if (input instanceof UserIdentifier) { + communityUUID = input.communityUuid + } else { + communityUUID = input + } + + if (cache.getHomeCommunityUUID() !== communityUUID) { + // it isn't home community so we can only retrieve public keys + let role: AbstractRemoteKeyPairRole + if (input instanceof UserIdentifier) { + role = new RemoteAccountKeyPairRole(input) + } else { + role = new ForeignCommunityKeyPairRole(input) + } + const keyPair = await role.retrieveKeyPair() + cache.addKeyPair(input, keyPair) + return keyPair + } + + let communityKeyPair = cache.findKeyPair(communityUUID) + if (!communityKeyPair) { + communityKeyPair = new HomeCommunityKeyPairRole().generateKeyPair() + cache.addKeyPair(communityUUID, communityKeyPair) + } + if (input instanceof UserIdentifier) { + const userKeyPair = new UserKeyPairRole(input, communityKeyPair).generateKeyPair() + const accountNr = input.accountNr ?? 1 + const accountKeyPair = new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() + cache.addKeyPair(input, accountKeyPair) + return accountKeyPair + } + return communityKeyPair +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts new file mode 100644 index 000000000..1cc9c9891 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -0,0 +1,35 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { getTransactions } from '@/client/GradidoNode' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { LogError } from '@/server/LogError' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' + +export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { + public constructor(private user: UserIdentifier) { + super() + } + + public async retrieveKeyPair(): Promise { + const nameHash = uuid4ToHash(this.user.uuid) + const confirmedTransactions = await getTransactions( + 0, + 30, + uuid4ToHash(this.user.communityUuid).convertToHex(), + ) + for (let i = 0; i < confirmedTransactions.length; i++) { + const transactionBody = confirmedTransactions[i].getGradidoTransaction()?.getTransactionBody() + if (transactionBody && transactionBody.isRegisterAddress()) { + const registerAddress = transactionBody.getRegisterAddress() + if (registerAddress && registerAddress.getNameHash()?.equal(nameHash)) { + return new KeyPairEd25519(registerAddress.getAccountPublicKey()) + } + } + } + throw new LogError( + 'cannot find remote user in first 30 transaction from remote blockchain, please wait for better recover implementation', + ) + } +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts new file mode 100644 index 000000000..473b203cd --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -0,0 +1,28 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { hardenDerivationIndex } from '@/utils/derivationHelper' +import { uuid4ToBuffer } from '@/utils/typeConverter' + +import { AbstractKeyPairRole } from './AbstractKeyPair.role' + +export class UserKeyPairRole extends AbstractKeyPairRole { + public constructor(private user: UserIdentifier, private communityKeys: KeyPairEd25519) { + super() + } + + public generateKeyPair(): KeyPairEd25519 { + // example gradido id: 03857ac1-9cc2-483e-8a91-e5b10f5b8d16 => + // wholeHex: '03857ac19cc2483e8a91e5b10f5b8d16'] + const wholeHex = uuid4ToBuffer(this.user.uuid) + const parts = [] + for (let i = 0; i < 4; i++) { + parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) + } + // parts: [2206563009, 2629978174, 2324817329, 2405141782] + return parts.reduce( + (keyPair: KeyPairEd25519, node: number) => keyPair.deriveChild(node), + this.communityKeys, + ) + } +} diff --git a/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts new file mode 100644 index 000000000..ac9120e3d --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts @@ -0,0 +1,7 @@ +import { GradidoTransactionBuilder } from 'gradido-blockchain-js' + +export abstract class AbstractTransactionRole { + abstract getGradidoTransactionBuilder(): Promise + abstract getSenderCommunityUuid(): string + abstract getRecipientCommunityUuid(): string +} diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts new file mode 100644 index 000000000..713a2b906 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts @@ -0,0 +1,47 @@ +import { GradidoTransactionBuilder } from 'gradido-blockchain-js' + +import { CommunityDraft } from '@/graphql/input/CommunityDraft' +import { LogError } from '@/server/LogError' +import { + AUF_ACCOUNT_DERIVATION_INDEX, + GMW_ACCOUNT_DERIVATION_INDEX, + hardenDerivationIndex, +} from '@/utils/derivationHelper' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class CommunityRootTransactionRole extends AbstractTransactionRole { + constructor(private self: CommunityDraft) { + super() + } + + getSenderCommunityUuid(): string { + return this.self.uuid + } + + getRecipientCommunityUuid(): string { + throw new LogError('cannot be used as cross group transaction') + } + + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const communityKeyPair = await KeyPairCalculation(this.self.uuid) + const gmwKeyPair = communityKeyPair.deriveChild( + hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), + ) + const aufKeyPair = communityKeyPair.deriveChild( + hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), + ) + builder + .setCreatedAt(new Date(this.self.createdAt)) + .setCommunityRoot( + communityKeyPair.getPublicKey(), + gmwKeyPair.getPublicKey(), + aufKeyPair.getPublicKey(), + ) + .sign(communityKeyPair) + return builder + } +} diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts new file mode 100644 index 000000000..0e80e19a4 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -0,0 +1,39 @@ +import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' + +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { LogError } from '@/server/LogError' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class CreationTransactionRole extends AbstractTransactionRole { + constructor(private self: TransactionDraft) { + super() + } + + getSenderCommunityUuid(): string { + return this.self.user.communityUuid + } + + getRecipientCommunityUuid(): string { + throw new LogError('cannot be used as cross group transaction') + } + + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const recipientKeyPair = await KeyPairCalculation(this.self.user) + const signerKeyPair = await KeyPairCalculation(this.self.linkedUser) + if (!this.self.targetDate) { + throw new LogError('target date missing for creation transaction') + } + builder + .setCreatedAt(new Date(this.self.createdAt)) + .setTransactionCreation( + new TransferAmount(recipientKeyPair.getPublicKey(), this.self.amount.toString()), + new Date(this.self.targetDate), + ) + .sign(signerKeyPair) + return builder + } +} diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts new file mode 100644 index 000000000..498e71bf7 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -0,0 +1,40 @@ +/* eslint-disable camelcase */ +import { AddressType_COMMUNITY_HUMAN, GradidoTransactionBuilder } from 'gradido-blockchain-js' + +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { LogError } from '@/server/LogError' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class RegisterAddressTransactionRole extends AbstractTransactionRole { + constructor(private self: UserAccountDraft) { + super() + } + + getSenderCommunityUuid(): string { + return this.self.user.communityUuid + } + + getRecipientCommunityUuid(): string { + throw new LogError('cannot yet be used as cross group transaction') + } + + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const communityKeyPair = await KeyPairCalculation(this.self.user.communityUuid) + const accountKeyPair = await KeyPairCalculation(this.self.user) + builder + .setCreatedAt(new Date(this.self.createdAt)) + .setRegisterAddress( + accountKeyPair.getPublicKey(), + AddressType_COMMUNITY_HUMAN, + uuid4ToHash(this.self.user.uuid), + ) + .sign(communityKeyPair) + .sign(accountKeyPair) + return builder + } +} diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts new file mode 100644 index 000000000..a10a95c35 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -0,0 +1,116 @@ +/* eslint-disable camelcase */ +import { + GradidoTransaction, + InteractionSerialize, + InteractionValidate, + MemoryBlock, + ValidateType_SINGLE, +} from 'gradido-blockchain-js' + +import { sendMessage as iotaSendMessage } from '@/client/IotaClient' +import { InputTransactionType } from '@/graphql/enum/InputTransactionType' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { CommunityDraft } from '@/graphql/input/CommunityDraft' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { TransactionError } from '@/graphql/model/TransactionError' +import { TransactionRecipe } from '@/graphql/model/TransactionRecipe' +import { TransactionResult } from '@/graphql/model/TransactionResult' +import { logger } from '@/logging/logger' +import { LogError } from '@/server/LogError' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { AbstractTransactionRole } from './AbstractTransaction.role' +import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' +import { CreationTransactionRole } from './CreationTransaction.role' +import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' +import { TransferTransactionRole } from './TransferTransaction.role' + +/** + * @DCI-Context + * Context for sending transaction to iota + * send every transaction only once to iota! + */ +export async function SendToIotaContext( + input: TransactionDraft | UserAccountDraft | CommunityDraft, +): Promise { + const validate = (transaction: GradidoTransaction): void => { + try { + // throw an exception when something is wrong + const validator = new InteractionValidate(transaction) + validator.run(ValidateType_SINGLE) + } catch (e) { + if (e instanceof Error) { + throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e.message) + } else if (typeof e === 'string') { + throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e) + } else { + throw e + } + } + } + + const sendViaIota = async ( + gradidoTransaction: GradidoTransaction, + topic: string, + ): Promise => { + // protobuf serializing function + const serialized = new InteractionSerialize(gradidoTransaction).run() + if (!serialized) { + throw new TransactionError( + TransactionErrorType.PROTO_ENCODE_ERROR, + 'cannot serialize transaction', + ) + } + const resultMessage = await iotaSendMessage( + Uint8Array.from(serialized.data()), + Uint8Array.from(Buffer.from(topic, 'hex')), + ) + logger.info('transmitted Gradido Transaction to Iota', { + messageId: resultMessage.messageId, + }) + return MemoryBlock.fromHex(resultMessage.messageId) + } + + let role: AbstractTransactionRole + if (input instanceof TransactionDraft) { + if (input.type === InputTransactionType.CREATION) { + role = new CreationTransactionRole(input) + } else if (input.type === InputTransactionType.SEND) { + role = new TransferTransactionRole(input) + } else { + throw new LogError('not supported transaction type') + } + } else if (input instanceof UserAccountDraft) { + role = new RegisterAddressTransactionRole(input) + } else if (input instanceof CommunityDraft) { + role = new CommunityRootTransactionRole(input) + } else { + throw new LogError('not expected input') + } + const builder = await role.getGradidoTransactionBuilder() + if (builder.isCrossCommunityTransaction()) { + const outboundTransaction = builder.buildOutbound() + validate(outboundTransaction) + const outboundIotaMessageId = await sendViaIota( + outboundTransaction, + uuid4ToHash(role.getSenderCommunityUuid()).convertToHex(), + ) + builder.setParentMessageId(outboundIotaMessageId) + const inboundTransaction = builder.buildInbound() + validate(inboundTransaction) + await sendViaIota( + inboundTransaction, + uuid4ToHash(role.getRecipientCommunityUuid()).convertToHex(), + ) + return new TransactionResult(new TransactionRecipe(outboundTransaction, outboundIotaMessageId)) + } else { + const transaction = builder.build() + validate(transaction) + const iotaMessageId = await sendViaIota( + transaction, + uuid4ToHash(role.getSenderCommunityUuid()).convertToHex(), + ) + return new TransactionResult(new TransactionRecipe(transaction, iotaMessageId)) + } +} diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts new file mode 100644 index 000000000..c26f8c61f --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -0,0 +1,44 @@ +import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' + +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class TransferTransactionRole extends AbstractTransactionRole { + constructor(private self: TransactionDraft) { + super() + } + + getSenderCommunityUuid(): string { + return this.self.user.communityUuid + } + + getRecipientCommunityUuid(): string { + return this.self.linkedUser.communityUuid + } + + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const senderKeyPair = await KeyPairCalculation(this.self.user) + const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + builder + .setCreatedAt(new Date(this.self.createdAt)) + .setTransactionTransfer( + new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), + recipientKeyPair.getPublicKey(), + ) + const senderCommunity = this.self.user.communityUuid + const recipientCommunity = this.self.linkedUser.communityUuid + if (senderCommunity !== recipientCommunity) { + // we have a cross group transaction + builder + .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) + .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) + } + builder.sign(senderKeyPair) + return builder + } +} diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/manager/KeyPairCacheManager.ts new file mode 100644 index 000000000..f5c11e388 --- /dev/null +++ b/dlt-connector/src/manager/KeyPairCacheManager.ts @@ -0,0 +1,66 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { LogError } from '@/server/LogError' + +// Source: https://refactoring.guru/design-patterns/singleton/typescript/example +// and ../federation/client/FederationClientFactory.ts +/** + * A Singleton class defines the `getInstance` method that lets clients access + * the unique singleton instance. + */ +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class KeyPairCacheManager { + // eslint-disable-next-line no-use-before-define + private static instance: KeyPairCacheManager + private cache: Map = new Map() + private homeCommunityUUID: string + + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor() {} + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(): KeyPairCacheManager { + if (!KeyPairCacheManager.instance) { + KeyPairCacheManager.instance = new KeyPairCacheManager() + } + return KeyPairCacheManager.instance + } + + public setHomeCommunityUUID(uuid: string): void { + this.homeCommunityUUID = uuid + } + + public getHomeCommunityUUID(): string { + return this.homeCommunityUUID + } + + public findKeyPair(input: UserIdentifier | string): KeyPairEd25519 | undefined { + return this.cache.get(this.getKey(input)) + } + + public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void { + const key = this.getKey(input) + if (this.cache.has(key)) { + throw new LogError('key already exist, cannot add', key) + } + this.cache.set(key, keyPair) + } + + protected getKey(input: UserIdentifier | string): string { + if (input instanceof UserIdentifier) { + return input.uuid + } else { + return input + } + } +} diff --git a/dlt-connector/src/utils/derivationHelper.ts b/dlt-connector/src/utils/derivationHelper.ts index 0431ec339..9de785306 100644 --- a/dlt-connector/src/utils/derivationHelper.ts +++ b/dlt-connector/src/utils/derivationHelper.ts @@ -1,4 +1,6 @@ export const HARDENED_KEY_BITMASK = 0x80000000 +export const GMW_ACCOUNT_DERIVATION_INDEX = 1 +export const AUF_ACCOUNT_DERIVATION_INDEX = 2 /* * change derivation index from x => x' diff --git a/dlt-connector/src/utils/typeConverter.test.ts b/dlt-connector/src/utils/typeConverter.test.ts index 05fb903b6..527e9dd17 100644 --- a/dlt-connector/src/utils/typeConverter.test.ts +++ b/dlt-connector/src/utils/typeConverter.test.ts @@ -1,6 +1,6 @@ import 'reflect-metadata' -import { base64ToBuffer, iotaTopicFromCommunityUUID, uuid4ToBuffer } from './typeConverter' +import { base64ToBuffer, uuid4ToHash, uuid4ToBuffer } from './typeConverter' describe('utils/typeConverter', () => { it('uuid4ToBuffer', () => { @@ -10,7 +10,7 @@ describe('utils/typeConverter', () => { }) it('iotaTopicFromCommunityUUID', () => { - expect(iotaTopicFromCommunityUUID('4f28e081-5c39-4dde-b6a4-3bde71de8d65')).toBe( + expect(uuid4ToHash('4f28e081-5c39-4dde-b6a4-3bde71de8d65')).toBe( '3138b3590311fdf0a823e173caa9487b7d275c23fab07106b4b1364cb038affd', ) }) diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 9290fdd82..198c15042 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -8,10 +8,14 @@ import { AddressType_CRYPTO_ACCOUNT, AddressType_NONE, AddressType_SUBACCOUNT, + ConfirmedTransaction, + DeserializeType_CONFIRMED_TRANSACTION, + InteractionDeserialize, + MemoryBlock, } from 'gradido-blockchain-js' -import { crypto_generichash as cryptoHash } from 'sodium-native' import { AccountType } from '@/graphql/enum/AccountType' +import { LogError } from '@/server/LogError' export const uuid4ToBuffer = (uuid: string): Buffer => { // Remove dashes from the UUIDv4 string @@ -23,10 +27,13 @@ export const uuid4ToBuffer = (uuid: string): Buffer => { return buffer } -export const iotaTopicFromCommunityUUID = (communityUUID: string): string => { - const hash = Buffer.alloc(32) - cryptoHash(hash, uuid4ToBuffer(communityUUID)) - return hash.toString('hex') +export const uuid4ToMemoryBlock = (uuid: string): MemoryBlock => { + // Remove dashes from the UUIDv4 string + return MemoryBlock.fromHex(uuid.replace(/-/g, '')) +} + +export const uuid4ToHash = (communityUUID: string): MemoryBlock => { + return uuid4ToMemoryBlock(communityUUID).calculateHash() } export const base64ToBuffer = (base64: string): Buffer => { @@ -86,3 +93,16 @@ export const addressTypeToAccountType = (type: AddressType): AccountType => { return AccountType.NONE } } + +export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { + const deserializer = new InteractionDeserialize( + MemoryBlock.fromBase64(base64), + DeserializeType_CONFIRMED_TRANSACTION, + ) + deserializer.run() + const confirmedTransaction = deserializer.getConfirmedTransaction() + if (!confirmedTransaction) { + throw new LogError("invalid data, couldn't deserialize") + } + return confirmedTransaction +} diff --git a/dlt-connector/test/seeding/Community.seed.ts b/dlt-connector/test/seeding/Community.seed.ts index 9c492eedb..8dee407f3 100644 --- a/dlt-connector/test/seeding/Community.seed.ts +++ b/dlt-connector/test/seeding/Community.seed.ts @@ -3,7 +3,7 @@ import { Community } from '@entity/Community' import { KeyPair } from '@/data/KeyPair' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' -import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter' +import { uuid4ToHash } from '@/utils/typeConverter' export const communitySeed = async ( uuid: string, @@ -14,7 +14,7 @@ export const communitySeed = async ( homeCommunityDraft.uuid = uuid homeCommunityDraft.foreign = foreign homeCommunityDraft.createdAt = new Date().toISOString() - const iotaTopic = iotaTopicFromCommunityUUID(uuid) + const iotaTopic = uuid4ToHash(uuid) const addCommunityContext = new AddCommunityContext(homeCommunityDraft, iotaTopic) await addCommunityContext.run() diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index 33c00a820..64ebb063a 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -1589,6 +1589,13 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + axios@^1.6.5: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" @@ -2254,7 +2261,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: +debug@4, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -2463,9 +2470,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.4: - version "1.5.26" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.26.tgz#449b4fa90e83ab98abbe3b6a96c8ee395de94452" - integrity sha512-Z+OMe9M/V6Ep9n/52+b7lkvYEps26z4Yz3vjWL1V61W0q+VLF1pOHhMY17sa4roz4AWmULSI8E6SAojZA5L0YQ== + version "1.5.27" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz#5203ce5d6054857d84ba84d3681cbe59132ade78" + integrity sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw== emittery@^0.8.1: version "0.8.1" @@ -3182,7 +3189,7 @@ flatted@^3.2.7, flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== -follow-redirects@^1.15.6: +follow-redirects@^1.14.4, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -3468,7 +3475,7 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: "gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js#master": version "0.0.1" - resolved "git+https://github.com/gradido/gradido-blockchain-js#02aaeefc015c8ec8b1a2c453d75e7c2cf803a7c2" + resolved "git+https://github.com/gradido/gradido-blockchain-js#5e7bc50af82d30ef0fdbe48414b1f916c592b6f4" dependencies: bindings "^1.5.0" nan "^2.20.0" @@ -4528,6 +4535,14 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonrpc-ts-client@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/jsonrpc-ts-client/-/jsonrpc-ts-client-0.2.3.tgz#ec50c413d84041564e6c8a4003ab4bb360d5cfcc" + integrity sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g== + dependencies: + axios "^0.24.0" + debug "^4.3.3" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -4554,9 +4569,9 @@ levn@^0.4.1: type-check "~0.4.0" libphonenumber-js@^1.10.53: - version "1.11.8" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.8.tgz#697fdd36500a97bc672d7927d867edf34b4bd2a7" - integrity sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg== + version "1.11.9" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz#e653042b11da2b50b7ea3b206fa7ca998436ae99" + integrity sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A== lines-and-columns@^1.1.6: version "1.2.4" From a826eaf83839d9a9a901745f2816fba518e4f2ce Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sun, 22 Sep 2024 17:01:59 +0200 Subject: [PATCH 009/226] cleanup not longer needed code --- dlt-connector/src/data/Account.factory.ts | 65 --- dlt-connector/src/data/Account.logic.ts | 35 -- dlt-connector/src/data/Account.repository.ts | 34 -- dlt-connector/src/data/Account.test.ts | 203 --------- .../src/data/Community.repository.ts | 82 ---- dlt-connector/src/data/KeyPair.ts | 107 ----- dlt-connector/src/data/Transaction.builder.ts | 153 ------- .../src/data/Transaction.repository.ts | 43 -- dlt-connector/src/data/User.factory.ts | 18 - dlt-connector/src/data/User.logic.ts | 42 -- dlt-connector/src/data/User.repository.ts | 32 -- dlt-connector/src/data/const.ts | 1 - .../data/proto/3_3/enum/TransactionType.ts | 13 - .../src/graphql/input/TransactionDraft.ts | 15 +- .../src/graphql/input/UserAccountDraft.ts | 3 +- .../src/graphql/resolver/AccountsResolver.ts | 54 +-- .../src/graphql/resolver/CommunityResolver.ts | 72 --- .../graphql/resolver/TransactionsResolver.ts | 42 +- dlt-connector/src/graphql/scalar/Decimal.ts | 30 -- dlt-connector/src/graphql/schema.ts | 6 +- .../src/graphql/validator/DateString.ts | 20 + .../src/graphql/validator/Decimal.ts | 22 - dlt-connector/src/index.ts | 17 +- .../account/RegisterAddress.context.ts | 65 --- .../community/AddCommunity.context.test.ts | 65 --- .../community/AddCommunity.context.ts | 31 -- .../backendToDb/community/Community.role.ts | 31 -- .../community/ForeignCommunity.role.ts | 4 - .../community/HomeCommunity.role.ts | 73 --- .../transaction/AbstractTransaction.role.ts | 36 -- .../AbstractTransactionRecipeRole.ts | 15 - .../BalanceChangingTransactionRecipeRole.ts | 40 -- .../CommunityRootTransaction.role.ts | 38 -- .../CreateTransactionRecipe.context.test.ts | 420 ------------------ .../CreateTransactionRecipe.context.ts | 89 ---- .../transaction/CreationTransaction.role.ts | 64 --- .../RegisterAddressTransaction.role.ts | 52 --- .../transaction/SendTransaction.role.ts | 35 -- .../RegisterAddressTransaction.role.ts | 6 +- .../AbstractTransactionRecipe.role.ts | 106 ----- .../InboundTransactionRecipe.role.ts | 44 -- .../LocalTransactionRecipe.role.ts | 24 - .../OutboundTransactionRecipeRole.ts | 10 - .../TransmitToIota.context.test.ts | 172 ------- .../transmitToIota/TransmitToIota.context.ts | 73 --- .../src/logging/AbstractLogging.view.ts | 8 - .../src/logging/AccountLogging.view.ts | 32 -- .../logging/BackendTransactionLogging.view.ts | 30 -- .../src/logging/CommunityLogging.view.ts | 24 - .../logging/TransactionDraftLogging.view.ts | 2 +- .../src/logging/TransactionLogging.view.ts | 66 --- dlt-connector/src/logging/UserLogging.view.ts | 20 - .../src/manager/InterruptiveSleepManager.ts | 63 --- dlt-connector/src/tasks/transmitToIota.ts | 49 -- dlt-connector/src/utils/InterruptiveSleep.ts | 31 -- 55 files changed, 65 insertions(+), 2862 deletions(-) delete mode 100644 dlt-connector/src/data/Account.factory.ts delete mode 100644 dlt-connector/src/data/Account.logic.ts delete mode 100644 dlt-connector/src/data/Account.repository.ts delete mode 100644 dlt-connector/src/data/Account.test.ts delete mode 100644 dlt-connector/src/data/Community.repository.ts delete mode 100644 dlt-connector/src/data/KeyPair.ts delete mode 100644 dlt-connector/src/data/Transaction.builder.ts delete mode 100644 dlt-connector/src/data/Transaction.repository.ts delete mode 100644 dlt-connector/src/data/User.factory.ts delete mode 100644 dlt-connector/src/data/User.logic.ts delete mode 100644 dlt-connector/src/data/User.repository.ts delete mode 100644 dlt-connector/src/data/const.ts delete mode 100644 dlt-connector/src/data/proto/3_3/enum/TransactionType.ts delete mode 100644 dlt-connector/src/graphql/resolver/CommunityResolver.ts delete mode 100755 dlt-connector/src/graphql/scalar/Decimal.ts delete mode 100644 dlt-connector/src/graphql/validator/Decimal.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.test.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/community/Community.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/community/ForeignCommunity.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts delete mode 100644 dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts delete mode 100644 dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts delete mode 100644 dlt-connector/src/logging/AccountLogging.view.ts delete mode 100644 dlt-connector/src/logging/BackendTransactionLogging.view.ts delete mode 100644 dlt-connector/src/logging/CommunityLogging.view.ts delete mode 100644 dlt-connector/src/logging/TransactionLogging.view.ts delete mode 100644 dlt-connector/src/logging/UserLogging.view.ts delete mode 100644 dlt-connector/src/manager/InterruptiveSleepManager.ts delete mode 100644 dlt-connector/src/tasks/transmitToIota.ts delete mode 100644 dlt-connector/src/utils/InterruptiveSleep.ts diff --git a/dlt-connector/src/data/Account.factory.ts b/dlt-connector/src/data/Account.factory.ts deleted file mode 100644 index fc20a0acc..000000000 --- a/dlt-connector/src/data/Account.factory.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable camelcase */ -import { Account } from '@entity/Account' -import Decimal from 'decimal.js-light' -import { - AddressType, - AddressType_COMMUNITY_AUF, - AddressType_COMMUNITY_GMW, -} from 'gradido-blockchain-js' - -import { KeyPair } from '@/data/KeyPair' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { hardenDerivationIndex } from '@/utils/derivationHelper' -import { accountTypeToAddressType } from '@/utils/typeConverter' - -const GMW_ACCOUNT_DERIVATION_INDEX = 1 -const AUF_ACCOUNT_DERIVATION_INDEX = 2 - -export class AccountFactory { - public static createAccount( - createdAt: Date, - derivationIndex: number, - type: AddressType, - parentKeyPair: KeyPair, - ): Account { - const account = Account.create() - account.derivationIndex = derivationIndex - account.derive2Pubkey = parentKeyPair.derive([derivationIndex]).publicKey - account.type = type.valueOf() - account.createdAt = createdAt - account.balanceOnConfirmation = new Decimal(0) - account.balanceOnCreation = new Decimal(0) - account.balanceCreatedAt = createdAt - return account - } - - public static createAccountFromUserAccountDraft( - { createdAt, accountType, user }: UserAccountDraft, - parentKeyPair: KeyPair, - ): Account { - return AccountFactory.createAccount( - new Date(createdAt), - user.accountNr ?? 1, - accountTypeToAddressType(accountType), - parentKeyPair, - ) - } - - public static createGmwAccount(keyPair: KeyPair, createdAt: Date): Account { - return AccountFactory.createAccount( - createdAt, - hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), - AddressType_COMMUNITY_GMW, - keyPair, - ) - } - - public static createAufAccount(keyPair: KeyPair, createdAt: Date): Account { - return AccountFactory.createAccount( - createdAt, - hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), - AddressType_COMMUNITY_AUF, - keyPair, - ) - } -} diff --git a/dlt-connector/src/data/Account.logic.ts b/dlt-connector/src/data/Account.logic.ts deleted file mode 100644 index 9cff66070..000000000 --- a/dlt-connector/src/data/Account.logic.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Account } from '@entity/Account' - -import { LogError } from '@/server/LogError' - -import { KeyPair } from './KeyPair' -import { UserLogic } from './User.logic' - -export class AccountLogic { - // eslint-disable-next-line no-useless-constructor - public constructor(private self: Account) {} - - /** - * calculate account key pair starting from community key pair => derive user key pair => derive account key pair - * @param communityKeyPair - */ - public calculateKeyPair(communityKeyPair: KeyPair): KeyPair { - if (!this.self.user) { - throw new LogError('missing user') - } - const userLogic = new UserLogic(this.self.user) - const accountKeyPair = userLogic - .calculateKeyPair(communityKeyPair) - .derive([this.self.derivationIndex]) - - if ( - this.self.derive2Pubkey && - this.self.derive2Pubkey.compare(accountKeyPair.publicKey) !== 0 - ) { - throw new LogError( - 'The freshly derived public key does not correspond to the stored public key', - ) - } - return accountKeyPair - } -} diff --git a/dlt-connector/src/data/Account.repository.ts b/dlt-connector/src/data/Account.repository.ts deleted file mode 100644 index 6931e6ea6..000000000 --- a/dlt-connector/src/data/Account.repository.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Account } from '@entity/Account' -import { User } from '@entity/User' -import { In } from 'typeorm' - -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { getDataSource } from '@/typeorm/DataSource' - -export const AccountRepository = getDataSource() - .getRepository(Account) - .extend({ - findAccountsByPublicKeys(publicKeys: Buffer[]): Promise { - return this.findBy({ derive2Pubkey: In(publicKeys) }) - }, - - async findAccountByPublicKey(publicKey: Buffer | undefined): Promise { - if (!publicKey) return undefined - return (await this.findOneBy({ derive2Pubkey: Buffer.from(publicKey) })) ?? undefined - }, - - async findAccountByUserIdentifier({ - uuid, - accountNr, - }: UserIdentifier): Promise { - const user = await User.findOne({ - where: { gradidoID: uuid, accounts: { derivationIndex: accountNr ?? 1 } }, - relations: { accounts: true }, - }) - if (user && user.accounts?.length === 1) { - const account = user.accounts[0] - account.user = user - return account - } - }, - }) diff --git a/dlt-connector/src/data/Account.test.ts b/dlt-connector/src/data/Account.test.ts deleted file mode 100644 index 130908de6..000000000 --- a/dlt-connector/src/data/Account.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* eslint-disable camelcase */ -import 'reflect-metadata' -import { Decimal } from 'decimal.js-light' - -import { TestDB } from '@test/TestDB' - -import { - AddressType_COMMUNITY_AUF, - AddressType_COMMUNITY_GMW, - AddressType_COMMUNITY_HUMAN, -} from 'gradido-blockchain-js' - -import { AccountType } from '@/graphql/enum/AccountType' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' - -import { AccountFactory } from './Account.factory' -import { AccountRepository } from './Account.repository' -import { KeyPair } from './KeyPair' -import { Mnemonic } from './Mnemonic' -import { UserFactory } from './User.factory' -import { UserLogic } from './User.logic' - -const con = TestDB.instance - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -describe('data/Account test factory and repository', () => { - const now = new Date() - const keyPair1 = new KeyPair(new Mnemonic('62ef251edc2416f162cd24ab1711982b')) - const keyPair2 = new KeyPair(new Mnemonic('000a0000000002000000000003000070')) - const keyPair3 = new KeyPair(new Mnemonic('00ba541a1000020000000000300bda70')) - const userGradidoID = '6be949ab-8198-4acf-ba63-740089081d61' - - describe('test factory methods', () => { - beforeAll(async () => { - await con.setupTestDB() - }) - afterAll(async () => { - await con.teardownTestDB() - }) - - it('test createAccount', () => { - const account = AccountFactory.createAccount(now, 1, AddressType_COMMUNITY_HUMAN, keyPair1) - expect(account).toMatchObject({ - derivationIndex: 1, - derive2Pubkey: Buffer.from( - 'cb88043ef4833afc01d6ed9b34e1aa48e79dce5ff97c07090c6600ec05f6d994', - 'hex', - ), - type: AddressType_COMMUNITY_HUMAN, - createdAt: now, - balanceCreatedAt: now, - balanceOnConfirmation: new Decimal(0), - balanceOnCreation: new Decimal(0), - }) - }) - - it('test createAccountFromUserAccountDraft', () => { - const userAccountDraft = new UserAccountDraft() - userAccountDraft.createdAt = now.toISOString() - userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN - userAccountDraft.user = new UserIdentifier() - userAccountDraft.user.accountNr = 1 - const account = AccountFactory.createAccountFromUserAccountDraft(userAccountDraft, keyPair1) - expect(account).toMatchObject({ - derivationIndex: 1, - derive2Pubkey: Buffer.from( - 'cb88043ef4833afc01d6ed9b34e1aa48e79dce5ff97c07090c6600ec05f6d994', - 'hex', - ), - type: AddressType_COMMUNITY_HUMAN, - createdAt: now, - balanceCreatedAt: now, - balanceOnConfirmation: new Decimal(0), - balanceOnCreation: new Decimal(0), - }) - }) - - it('test createGmwAccount', () => { - const account = AccountFactory.createGmwAccount(keyPair1, now) - expect(account).toMatchObject({ - derivationIndex: 2147483649, - derive2Pubkey: Buffer.from( - '05f0060357bb73bd290283870fc47a10b3764f02ca26938479ed853f46145366', - 'hex', - ), - type: AddressType_COMMUNITY_GMW, - createdAt: now, - balanceCreatedAt: now, - balanceOnConfirmation: new Decimal(0), - balanceOnCreation: new Decimal(0), - }) - }) - - it('test createAufAccount', () => { - const account = AccountFactory.createAufAccount(keyPair1, now) - expect(account).toMatchObject({ - derivationIndex: 2147483650, - derive2Pubkey: Buffer.from( - '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', - 'hex', - ), - type: AddressType_COMMUNITY_AUF, - createdAt: now, - balanceCreatedAt: now, - balanceOnConfirmation: new Decimal(0), - balanceOnCreation: new Decimal(0), - }) - }) - }) - - describe('test repository functions', () => { - beforeAll(async () => { - await con.setupTestDB() - await Promise.all([ - AccountFactory.createAufAccount(keyPair1, now).save(), - AccountFactory.createGmwAccount(keyPair1, now).save(), - AccountFactory.createAufAccount(keyPair2, now).save(), - AccountFactory.createGmwAccount(keyPair2, now).save(), - AccountFactory.createAufAccount(keyPair3, now).save(), - AccountFactory.createGmwAccount(keyPair3, now).save(), - ]) - const userAccountDraft = new UserAccountDraft() - userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN - userAccountDraft.createdAt = now.toString() - userAccountDraft.user = new UserIdentifier() - userAccountDraft.user.accountNr = 1 - userAccountDraft.user.uuid = userGradidoID - const user = UserFactory.create(userAccountDraft, keyPair1) - const userLogic = new UserLogic(user) - const account = AccountFactory.createAccountFromUserAccountDraft( - userAccountDraft, - userLogic.calculateKeyPair(keyPair1), - ) - account.user = user - // user is set to cascade: ['insert'] will be saved together with account - await account.save() - }) - afterAll(async () => { - await con.teardownTestDB() - }) - it('test findAccountsByPublicKeys', async () => { - const accounts = await AccountRepository.findAccountsByPublicKeys([ - Buffer.from('6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex'), - Buffer.from('0fa996b73b624592fe326b8500cb1e3f10026112b374d84c87d097f4d489c019', 'hex'), - Buffer.from('0ffa996b73b624592f26b850b0cb1e3f1026112b374d84c87d017f4d489c0197', 'hex'), // invalid - ]) - expect(accounts).toHaveLength(2) - expect(accounts).toMatchObject( - expect.arrayContaining([ - expect.objectContaining({ - derivationIndex: 2147483649, - derive2Pubkey: Buffer.from( - '0fa996b73b624592fe326b8500cb1e3f10026112b374d84c87d097f4d489c019', - 'hex', - ), - type: AddressType_COMMUNITY_GMW, - }), - expect.objectContaining({ - derivationIndex: 2147483650, - derive2Pubkey: Buffer.from( - '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', - 'hex', - ), - type: AddressType_COMMUNITY_AUF, - }), - ]), - ) - }) - - it('test findAccountByPublicKey', async () => { - expect( - await AccountRepository.findAccountByPublicKey( - Buffer.from('6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex'), - ), - ).toMatchObject({ - derivationIndex: 2147483650, - derive2Pubkey: Buffer.from( - '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', - 'hex', - ), - type: AddressType_COMMUNITY_AUF, - }) - }) - - it('test findAccountByUserIdentifier', async () => { - const userIdentifier = new UserIdentifier() - userIdentifier.accountNr = 1 - userIdentifier.uuid = userGradidoID - expect(await AccountRepository.findAccountByUserIdentifier(userIdentifier)).toMatchObject({ - derivationIndex: 1, - derive2Pubkey: Buffer.from( - '2099c004a26e5387c9fbbc9bb0f552a9642d3fd7c710ae5802b775d24ff36f93', - 'hex', - ), - type: AddressType_COMMUNITY_HUMAN, - }) - }) - }) -}) diff --git a/dlt-connector/src/data/Community.repository.ts b/dlt-connector/src/data/Community.repository.ts deleted file mode 100644 index eb52fb38c..000000000 --- a/dlt-connector/src/data/Community.repository.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Community } from '@entity/Community' -import { FindOptionsSelect, In, IsNull, Not } from 'typeorm' - -import { CommunityArg } from '@/graphql/arg/CommunityArg' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { TransactionError } from '@/graphql/model/TransactionError' -import { LogError } from '@/server/LogError' -import { getDataSource } from '@/typeorm/DataSource' -import { uuid4ToHash } from '@/utils/typeConverter' - -import { KeyPair } from './KeyPair' - -export const CommunityRepository = getDataSource() - .getRepository(Community) - .extend({ - async isExist(community: CommunityDraft | string): Promise { - const iotaTopic = - community instanceof CommunityDraft ? uuid4ToHash(community.uuid) : community - const result = await this.find({ - where: { iotaTopic }, - }) - return result.length > 0 - }, - - async findByCommunityArg({ uuid, foreign, confirmed }: CommunityArg): Promise { - return await this.find({ - where: { - ...(uuid && { iotaTopic: uuid4ToHash(uuid) }), - ...(foreign && { foreign }), - ...(confirmed && { confirmedAt: Not(IsNull()) }), - }, - }) - }, - - async findByCommunityUuid(communityUuid: string): Promise { - return await this.findOneBy({ iotaTopic: uuid4ToHash(communityUuid) }) - }, - - async findByIotaTopic(iotaTopic: string): Promise { - return await this.findOneBy({ iotaTopic }) - }, - - findCommunitiesByTopics(topics: string[]): Promise { - return this.findBy({ iotaTopic: In(topics) }) - }, - - async getCommunityForUserIdentifier( - identifier: UserIdentifier, - ): Promise { - if (!identifier.communityUuid) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community uuid not set') - } - return ( - (await this.findOneBy({ - iotaTopic: uuid4ToHash(identifier.communityUuid), - })) ?? undefined - ) - }, - - findAll(select: FindOptionsSelect): Promise { - return this.find({ select }) - }, - - async loadHomeCommunityKeyPair(): Promise { - const community = await this.findOneOrFail({ - where: { foreign: false }, - select: { rootChaincode: true, rootPubkey: true, rootEncryptedPrivkey: true }, - }) - if (!community.rootChaincode || !community.rootEncryptedPrivkey) { - throw new LogError('Missing chaincode or private key for home community') - } - return new KeyPair(community) - }, - - async loadHomeCommunity(): Promise { - return await this.findOneOrFail({ - where: { foreign: false }, - }) - }, - }) diff --git a/dlt-connector/src/data/KeyPair.ts b/dlt-connector/src/data/KeyPair.ts deleted file mode 100644 index 61207ee7e..000000000 --- a/dlt-connector/src/data/KeyPair.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Community } from '@entity/Community' -// https://www.npmjs.com/package/bip32-ed25519 -import { - KeyPairEd25519, - MemoryBlock, - Passphrase, - SecretKeyCryptography, - SignaturePair, -} from 'gradido-blockchain-js' - -import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' - -/** - * Class Managing Key Pair and also generate, sign and verify signature with it - */ -export class KeyPair { - private _ed25519KeyPair: KeyPairEd25519 - /** - * @param input: KeyPairEd25519 = already loaded KeyPairEd25519 - * @param input: Passphrase = Passphrase which work as seed for generating algorithms - * @param input: MemoryBlock = a seed at least 32 byte - * @param input: Community = community entity with keys loaded from db - */ - public constructor(input: KeyPairEd25519 | Passphrase | MemoryBlock | Community) { - let keyPair: KeyPairEd25519 | null = null - if (input instanceof KeyPairEd25519) { - keyPair = input - } else if (input instanceof Passphrase) { - keyPair = KeyPairEd25519.create(input) - } else if (input instanceof MemoryBlock) { - keyPair = KeyPairEd25519.create(input) - } else if (input instanceof Community) { - if (!input.rootEncryptedPrivkey || !input.rootChaincode || !input.rootPubkey) { - throw new LogError( - 'missing encrypted private key or chaincode or public key in commmunity entity', - ) - } - const secretBox = this.createSecretBox(input.iotaTopic) - keyPair = new KeyPairEd25519( - new MemoryBlock(input.rootPubkey), - secretBox.decrypt(new MemoryBlock(input.rootEncryptedPrivkey)), - new MemoryBlock(input.rootChaincode), - ) - } - if (!keyPair) { - throw new LogError("couldn't create KeyPairEd25519 from input") - } - this._ed25519KeyPair = keyPair - } - - /** - * copy keys to community entity - * @param community - */ - public fillInCommunityKeys(community: Community) { - const secretBox = this.createSecretBox(community.iotaTopic) - community.rootPubkey = this._ed25519KeyPair.getPublicKey()?.data() - community.rootEncryptedPrivkey = this._ed25519KeyPair.getCryptedPrivKey(secretBox).data() - community.rootChaincode = this._ed25519KeyPair.getChainCode()?.data() - } - - public get publicKey(): Buffer { - const publicKey = this._ed25519KeyPair.getPublicKey() - if (!publicKey) { - throw new LogError('invalid key pair, get empty public key') - } - return publicKey.data() - } - - public get keyPair(): KeyPairEd25519 { - return this._ed25519KeyPair - } - - public derive(path: number[]): KeyPair { - return new KeyPair( - path.reduce( - (keyPair: KeyPairEd25519, node: number) => keyPair.deriveChild(node), - this._ed25519KeyPair, - ), - ) - } - - public sign(message: Buffer): Buffer { - return this._ed25519KeyPair.sign(new MemoryBlock(message)).data() - } - - public static verify(message: Buffer, signaturePair: SignaturePair): boolean { - const publicKeyPair = new KeyPairEd25519(signaturePair.getPubkey()) - const signature = signaturePair.getSignature() - if (!signature) { - throw new LogError('missing signature') - } - return publicKeyPair.verify(new MemoryBlock(message), signature) - } - - private createSecretBox(salt: string): SecretKeyCryptography { - if (!CONFIG.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD) { - throw new LogError( - 'missing GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD in env or config', - ) - } - const secretBox = new SecretKeyCryptography() - secretBox.createKey(salt, CONFIG.GRADIDO_BLOCKCHAIN_PRIVATE_KEY_ENCRYPTION_PASSWORD) - return secretBox - } -} diff --git a/dlt-connector/src/data/Transaction.builder.ts b/dlt-connector/src/data/Transaction.builder.ts deleted file mode 100644 index a07ed8589..000000000 --- a/dlt-connector/src/data/Transaction.builder.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Account } from '@entity/Account' -import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' -import { - GradidoTransaction, - InteractionSerialize, - InteractionToJson, - TransactionBody, -} from 'gradido-blockchain-js' - -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { LogError } from '@/server/LogError' - -import { CommunityRepository } from './Community.repository' - -export class TransactionBuilder { - private transaction: Transaction - - // https://refactoring.guru/design-patterns/builder/typescript/example - /** - * A fresh builder instance should contain a blank product object, which is - * used in further assembly. - */ - constructor() { - this.reset() - } - - public reset(): void { - this.transaction = Transaction.create() - } - - /** - * Concrete Builders are supposed to provide their own methods for - * retrieving results. That's because various types of builders may create - * entirely different products that don't follow the same interface. - * Therefore, such methods cannot be declared in the base Builder interface - * (at least in a statically typed programming language). - * - * Usually, after returning the end result to the client, a builder instance - * is expected to be ready to start producing another product. That's why - * it's a usual practice to call the reset method at the end of the - * `getProduct` method body. However, this behavior is not mandatory, and - * you can make your builders wait for an explicit reset call from the - * client code before disposing of the previous result. - */ - public build(): Transaction { - const result = this.transaction - this.reset() - return result - } - - // return transaction without calling reset - public getTransaction(): Transaction { - return this.transaction - } - - public getCommunity(): Community { - return this.transaction.community - } - - public getOtherCommunity(): Community | undefined { - return this.transaction.otherCommunity - } - - public setSigningAccount(signingAccount: Account): TransactionBuilder { - this.transaction.signingAccount = signingAccount - return this - } - - public setRecipientAccount(recipientAccount: Account): TransactionBuilder { - this.transaction.recipientAccount = recipientAccount - return this - } - - public setCommunity(community: Community): TransactionBuilder { - this.transaction.community = community - return this - } - - public setOtherCommunity(otherCommunity?: Community): TransactionBuilder { - if (!this.transaction.community) { - throw new LogError('Please set community first!') - } - - this.transaction.otherCommunity = - otherCommunity && - this.transaction.community && - this.transaction.community.id !== otherCommunity.id - ? otherCommunity - : undefined - return this - } - - public setSignature(signature: Buffer): TransactionBuilder { - this.transaction.signature = signature - return this - } - - public async setCommunityFromUser(user: UserIdentifier): Promise { - // get sender community - const community = await CommunityRepository.getCommunityForUserIdentifier(user) - if (!community) { - throw new LogError("couldn't find community for transaction") - } - return this.setCommunity(community) - } - - public async setOtherCommunityFromUser(user: UserIdentifier): Promise { - // get recipient community - const otherCommunity = await CommunityRepository.getCommunityForUserIdentifier(user) - return this.setOtherCommunity(otherCommunity) - } - - public fromGradidoTransaction(transaction: GradidoTransaction): TransactionBuilder { - const body = transaction.getTransactionBody() - if (!body) { - throw new LogError('missing transaction body on Gradido Transaction') - } - // set first signature - const firstSignature = transaction.getSignatureMap().getSignaturePairs().get(0).getSignature() - if (!firstSignature) { - throw new LogError('error missing first signature') - } - this.transaction.signature = firstSignature.data() - return this.fromTransactionBody(body, transaction.getBodyBytes()?.data()) - } - - public fromTransactionBody( - transactionBody: TransactionBody, - bodyBytes: Buffer | null | undefined, - ): TransactionBuilder { - if (!bodyBytes) { - bodyBytes = new InteractionSerialize(transactionBody).run()?.data() - } - if (!bodyBytes) { - throw new LogError( - 'cannot serialize TransactionBody', - JSON.parse(new InteractionToJson(transactionBody).run()), - ) - } - this.transaction.type = transactionBody.getTransactionType() - this.transaction.createdAt = new Date(transactionBody.getCreatedAt().getDate()) - this.transaction.protocolVersion = transactionBody.getVersionNumber() - - const transferAmount = transactionBody.getTransferAmount() - this.transaction.amount = transferAmount - ? transferAmount.getAmount().getGradidoCent() - : undefined - - this.transaction.bodyBytes ??= bodyBytes - return this - } -} diff --git a/dlt-connector/src/data/Transaction.repository.ts b/dlt-connector/src/data/Transaction.repository.ts deleted file mode 100644 index 6ba622c9c..000000000 --- a/dlt-connector/src/data/Transaction.repository.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Transaction } from '@entity/Transaction' -import { IsNull } from 'typeorm' - -import { getDataSource } from '@/typeorm/DataSource' - -// https://www.artima.com/articles/the-dci-architecture-a-new-vision-of-object-oriented-programming -export const TransactionRepository = getDataSource() - .getRepository(Transaction) - .extend({ - findBySignature(signature: Buffer): Promise { - return this.findOneBy({ signature: Buffer.from(signature) }) - }, - findByMessageId(iotaMessageId: string): Promise { - return this.findOneBy({ iotaMessageId: Buffer.from(iotaMessageId, 'hex') }) - }, - async getNextPendingTransaction(): Promise { - return await this.findOne({ - where: { iotaMessageId: IsNull() }, - order: { createdAt: 'ASC' }, - relations: { signingAccount: true }, - }) - }, - findExistingTransactionAndMissingMessageIds(messageIDsHex: string[]): Promise { - return this.createQueryBuilder('Transaction') - .where('HEX(Transaction.iota_message_id) IN (:...messageIDs)', { - messageIDs: messageIDsHex, - }) - .leftJoinAndSelect('Transaction.community', 'Community') - .leftJoinAndSelect('Transaction.otherCommunity', 'OtherCommunity') - .leftJoinAndSelect('Transaction.recipientAccount', 'RecipientAccount') - .leftJoinAndSelect('Transaction.backendTransactions', 'BackendTransactions') - .leftJoinAndSelect('RecipientAccount.user', 'RecipientUser') - .leftJoinAndSelect('Transaction.signingAccount', 'SigningAccount') - .leftJoinAndSelect('SigningAccount.user', 'SigningUser') - .getMany() - }, - removeConfirmedTransaction(transactions: Transaction[]): Transaction[] { - return transactions.filter( - (transaction: Transaction) => - transaction.runningHash === undefined || transaction.runningHash.length === 0, - ) - }, - }) diff --git a/dlt-connector/src/data/User.factory.ts b/dlt-connector/src/data/User.factory.ts deleted file mode 100644 index a8c7f0e71..000000000 --- a/dlt-connector/src/data/User.factory.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { User } from '@entity/User' - -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' - -import { KeyPair } from './KeyPair' -import { UserLogic } from './User.logic' - -export class UserFactory { - static create(userAccountDraft: UserAccountDraft, parentKeys: KeyPair): User { - const user = User.create() - user.createdAt = new Date(userAccountDraft.createdAt) - user.gradidoID = userAccountDraft.user.uuid - const userLogic = new UserLogic(user) - // store generated pubkey into entity - userLogic.calculateKeyPair(parentKeys) - return user - } -} diff --git a/dlt-connector/src/data/User.logic.ts b/dlt-connector/src/data/User.logic.ts deleted file mode 100644 index 8bffe326e..000000000 --- a/dlt-connector/src/data/User.logic.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { User } from '@entity/User' - -import { LogError } from '@/server/LogError' -import { hardenDerivationIndex } from '@/utils/derivationHelper' -import { uuid4ToBuffer } from '@/utils/typeConverter' - -import { KeyPair } from './KeyPair' - -export class UserLogic { - // eslint-disable-next-line no-useless-constructor - constructor(private user: User) {} - - /** - * - * @param parentKeys from home community for own user - * @returns - */ - - calculateKeyPair = (parentKeys: KeyPair): KeyPair => { - if (!this.user.gradidoID) { - throw new LogError('missing GradidoID for user.', { id: this.user.id }) - } - // example gradido id: 03857ac1-9cc2-483e-8a91-e5b10f5b8d16 => - // wholeHex: '03857ac19cc2483e8a91e5b10f5b8d16'] - const wholeHex = uuid4ToBuffer(this.user.gradidoID) - const parts = [] - for (let i = 0; i < 4; i++) { - parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) - } - // parts: [2206563009, 2629978174, 2324817329, 2405141782] - const keyPair = parentKeys.derive(parts) - if (this.user.derive1Pubkey && this.user.derive1Pubkey.compare(keyPair.publicKey) !== 0) { - throw new LogError( - 'The freshly derived public key does not correspond to the stored public key', - ) - } - if (!this.user.derive1Pubkey) { - this.user.derive1Pubkey = keyPair.publicKey - } - return keyPair - } -} diff --git a/dlt-connector/src/data/User.repository.ts b/dlt-connector/src/data/User.repository.ts deleted file mode 100644 index 1e9e4dcef..000000000 --- a/dlt-connector/src/data/User.repository.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Account } from '@entity/Account' -import { User } from '@entity/User' -import { FindOptionsRelations } from 'typeorm' - -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { getDataSource } from '@/typeorm/DataSource' - -export const UserRepository = getDataSource() - .getRepository(User) - .extend({ - async findAccountByUserIdentifier({ - uuid, - accountNr, - }: UserIdentifier): Promise { - const user = await this.findOne({ - where: { gradidoID: uuid, accounts: { derivationIndex: accountNr ?? 1 } }, - relations: { accounts: true }, - }) - if (user && user.accounts?.length === 1) { - const account = user.accounts[0] - account.user = user - return account - } - }, - - findByGradidoId( - { uuid }: UserIdentifier, - relations?: FindOptionsRelations, - ): Promise { - return User.findOne({ where: { gradidoID: uuid }, relations }) - }, - }) diff --git a/dlt-connector/src/data/const.ts b/dlt-connector/src/data/const.ts deleted file mode 100644 index 82470e8d4..000000000 --- a/dlt-connector/src/data/const.ts +++ /dev/null @@ -1 +0,0 @@ -export const TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY = 'transmitToIota' diff --git a/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts b/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts deleted file mode 100644 index 07bf5c393..000000000 --- a/dlt-connector/src/data/proto/3_3/enum/TransactionType.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * based on TransactionBody data oneOf - * https://github.com/gradido/gradido_protocol/blob/master/proto/gradido/transaction_body.proto - * for storing type in db as number - */ -export enum TransactionType { - GRADIDO_CREATION = 1, - GRADIDO_TRANSFER = 2, - GROUP_FRIENDS_UPDATE = 3, - REGISTER_ADDRESS = 4, - GRADIDO_DEFERRED_TRANSFER = 5, - COMMUNITY_ROOT = 6, -} diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 541797565..59e1ecafd 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,11 +1,8 @@ // https://www.npmjs.com/package/@apollo/protobufjs -import { IsEnum, IsObject, IsPositive, ValidateNested } from 'class-validator' -import { Decimal } from 'decimal.js-light' -import { InputType, Field, Int } from 'type-graphql' - import { InputTransactionType } from '@enum/InputTransactionType' -import { isValidDateString } from '@validator/DateString' -import { IsPositiveDecimal } from '@validator/Decimal' +import { isValidDateString, isValidNumberString } from '@validator/DateString' +import { IsEnum, IsObject, IsPositive, ValidateNested } from 'class-validator' +import { InputType, Field, Int } from 'type-graphql' import { UserIdentifier } from './UserIdentifier' @@ -25,9 +22,9 @@ export class TransactionDraft { @IsPositive() backendTransactionId: number - @Field(() => Decimal) - @IsPositiveDecimal() - amount: Decimal + @Field(() => String) + @isValidNumberString() + amount: string @Field(() => InputTransactionType) @IsEnum(InputTransactionType) diff --git a/dlt-connector/src/graphql/input/UserAccountDraft.ts b/dlt-connector/src/graphql/input/UserAccountDraft.ts index 9ae544e32..e10be9574 100644 --- a/dlt-connector/src/graphql/input/UserAccountDraft.ts +++ b/dlt-connector/src/graphql/input/UserAccountDraft.ts @@ -1,10 +1,9 @@ // https://www.npmjs.com/package/@apollo/protobufjs +import { isValidDateString } from '@validator/DateString' import { IsEnum, IsObject, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' -import { isValidDateString } from '@validator/DateString' - import { AccountType } from '@/graphql/enum/AccountType' import { UserIdentifier } from './UserIdentifier' diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts index 7f782af89..a7f264764 100644 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -1,16 +1,12 @@ +/* eslint-disable camelcase */ +import { AddressType_NONE } from 'gradido-blockchain-js' import { Arg, Mutation, Query, Resolver } from 'type-graphql' -import { QueryFailedError } from 'typeorm' -import { TransactionRecipe } from '@model/TransactionRecipe' - -import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' -import { UserRepository } from '@/data/User.repository' -import { RegisterAddressContext } from '@/interactions/backendToDb/account/RegisterAddress.context' -import { AccountLoggingView } from '@/logging/AccountLogging.view' +import { getAddressType } from '@/client/GradidoNode' +import { KeyPairCalculation } from '@/interactions/keyPairCalculation/KeyPairCalculation.context' +import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' import { logger } from '@/logging/logger' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' -import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' -import { getDataSource } from '@/typeorm/DataSource' +import { uuid4ToHash } from '@/utils/typeConverter' import { TransactionErrorType } from '../enum/TransactionErrorType' import { UserAccountDraft } from '../input/UserAccountDraft' @@ -22,8 +18,20 @@ import { TransactionResult } from '../model/TransactionResult' export class AccountResolver { @Query(() => Boolean) async isAccountExist(@Arg('data') userIdentifier: UserIdentifier): Promise { + const accountKeyPair = await KeyPairCalculation(userIdentifier) + const publicKey = accountKeyPair.getPublicKey() + if (!publicKey) { + throw new TransactionResult( + new TransactionError(TransactionErrorType.NOT_FOUND, 'cannot get user public key'), + ) + } + // ask gradido node server for account type, if type !== NONE account exist + const addressType = await getAddressType( + publicKey.data(), + uuid4ToHash(userIdentifier.communityUuid).convertToHex(), + ) logger.info('isAccountExist', userIdentifier) - return !!(await UserRepository.findAccountByUserIdentifier(userIdentifier)) + return addressType !== AddressType_NONE } @Mutation(() => TransactionResult) @@ -31,30 +39,10 @@ export class AccountResolver { @Arg('data') userAccountDraft: UserAccountDraft, ): Promise { - const registerAddressContext = new RegisterAddressContext(userAccountDraft) try { - const { transaction, account } = await registerAddressContext.run() - logger.info('register address', { - account: new AccountLoggingView(account), - transaction: new TransactionLoggingView(transaction), - }) - await getDataSource().transaction(async (transactionalEntityManager) => { - await transactionalEntityManager.save(account) - await transactionalEntityManager.save(transaction) - logger.debug('store register address transaction', new TransactionLoggingView(transaction)) - }) - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - return new TransactionResult(new TransactionRecipe(transaction)) + return await SendToIotaContext(userAccountDraft) } catch (err) { - if (err instanceof QueryFailedError) { - logger.error('error saving user or new account or transaction into db: %s', err) - return new TransactionResult( - new TransactionError( - TransactionErrorType.DB_ERROR, - 'error saving user or new account or transaction into db', - ), - ) - } else if (err instanceof TransactionError) { + if (err instanceof TransactionError) { return new TransactionResult(err) } else { logger.error('error in register address: ', err) diff --git a/dlt-connector/src/graphql/resolver/CommunityResolver.ts b/dlt-connector/src/graphql/resolver/CommunityResolver.ts deleted file mode 100644 index 848dd0733..000000000 --- a/dlt-connector/src/graphql/resolver/CommunityResolver.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { CommunityArg } from '@arg/CommunityArg' -import { TransactionErrorType } from '@enum/TransactionErrorType' -import { CommunityDraft } from '@input/CommunityDraft' -import { Community } from '@model/Community' -import { TransactionError } from '@model/TransactionError' -import { TransactionResult } from '@model/TransactionResult' -import { Resolver, Query, Arg, Mutation, Args } from 'type-graphql' - -import { CommunityRepository } from '@/data/Community.repository' -import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' - -@Resolver() -export class CommunityResolver { - @Query(() => Community) - async community(@Args() communityArg: CommunityArg): Promise { - logger.info('community', communityArg) - const result = await CommunityRepository.findByCommunityArg(communityArg) - if (result.length === 0) { - throw new LogError('cannot find community') - } else if (result.length === 1) { - return new Community(result[0]) - } else { - throw new LogError('find multiple communities') - } - } - - @Query(() => Boolean) - async isCommunityExist(@Args() communityArg: CommunityArg): Promise { - logger.info('isCommunity', communityArg) - return (await CommunityRepository.findByCommunityArg(communityArg)).length === 1 - } - - @Query(() => [Community]) - async communities(@Args() communityArg: CommunityArg): Promise { - logger.info('communities', communityArg) - const result = await CommunityRepository.findByCommunityArg(communityArg) - return result.map((communityEntity) => new Community(communityEntity)) - } - - @Mutation(() => TransactionResult) - async addCommunity( - @Arg('data') - communityDraft: CommunityDraft, - ): Promise { - logger.info('addCommunity', communityDraft) - const topic = uuid4ToHash(communityDraft.uuid) - // check if community was already written to db - if (await CommunityRepository.isExist(topic)) { - return new TransactionResult( - new TransactionError(TransactionErrorType.ALREADY_EXIST, 'community already exist!'), - ) - } - // prepare context for interaction - // shouldn't throw at all - // TODO: write tests to make sure that it doesn't throw - const addCommunityContext = new AddCommunityContext(communityDraft, topic) - try { - // actually run interaction, create community, accounts for foreign community and transactionRecipe - await addCommunityContext.run() - return new TransactionResult() - } catch (error) { - if (error instanceof TransactionError) { - return new TransactionResult(error) - } else { - throw error - } - } - } -} diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 8302a872f..50636dee3 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,17 +1,9 @@ +import { TransactionDraft } from '@input/TransactionDraft' import { Resolver, Arg, Mutation } from 'type-graphql' -import { TransactionDraft } from '@input/TransactionDraft' +import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' -import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' -import { TransactionRepository } from '@/data/Transaction.repository' -import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransactionRecipe.context' -import { logger } from '@/logging/logger' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' -import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' - -import { TransactionErrorType } from '../enum/TransactionErrorType' import { TransactionError } from '../model/TransactionError' -import { TransactionRecipe } from '../model/TransactionRecipe' import { TransactionResult } from '../model/TransactionResult' @Resolver() @@ -21,36 +13,8 @@ export class TransactionResolver { @Arg('data') transactionDraft: TransactionDraft, ): Promise { - const createTransactionRecipeContext = new CreateTransactionRecipeContext(transactionDraft) try { - const result = await createTransactionRecipeContext.run() - if (!result) { - return new TransactionResult( - new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'cannot work with this parameters', - ), - ) - } - const transactionRecipe = createTransactionRecipeContext.getTransactionRecipe() - // check if a transaction with this signature already exist - const existingRecipe = await TransactionRepository.findBySignature( - transactionRecipe.signature, - ) - if (existingRecipe) { - return new TransactionResult( - new TransactionError( - TransactionErrorType.ALREADY_EXIST, - 'Transaction with same signature already exist', - ), - ) - } else { - logger.debug('store transaction recipe', new TransactionLoggingView(transactionRecipe)) - // we store the transaction - await transactionRecipe.save() - } - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - return new TransactionResult(new TransactionRecipe(transactionRecipe)) + return await SendToIotaContext(transactionDraft) // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { if (error instanceof TransactionError) { diff --git a/dlt-connector/src/graphql/scalar/Decimal.ts b/dlt-connector/src/graphql/scalar/Decimal.ts deleted file mode 100755 index b343f383a..000000000 --- a/dlt-connector/src/graphql/scalar/Decimal.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { Decimal } from 'decimal.js-light' -import { GraphQLScalarType, Kind, ValueNode } from 'graphql' - -export const DecimalScalar = new GraphQLScalarType({ - name: 'Decimal', - description: 'The `Decimal` scalar type to represent currency values', - - serialize(value: unknown): string { - if (!(value instanceof Decimal)) { - throw new TypeError(`Value is not a Decimal: ${value}`) - } - return value.toString() - }, - - parseValue(value: unknown): Decimal { - if (typeof value !== 'string') { - throw new TypeError('Decimal values must be strings') - } - return new Decimal(value) - }, - - parseLiteral(ast: ValueNode): Decimal { - if (ast.kind !== Kind.STRING) { - throw new TypeError(`${String(ast)} is not a valid decimal value.`) - } - - return new Decimal(ast.value) - }, -}) diff --git a/dlt-connector/src/graphql/schema.ts b/dlt-connector/src/graphql/schema.ts index a756b1ac9..f0e2f7198 100755 --- a/dlt-connector/src/graphql/schema.ts +++ b/dlt-connector/src/graphql/schema.ts @@ -1,16 +1,12 @@ -import { Decimal } from 'decimal.js-light' import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' import { AccountResolver } from './resolver/AccountsResolver' -import { CommunityResolver } from './resolver/CommunityResolver' import { TransactionResolver } from './resolver/TransactionsResolver' -import { DecimalScalar } from './scalar/Decimal' export const schema = async (): Promise => { return buildSchema({ - resolvers: [TransactionResolver, CommunityResolver, AccountResolver], - scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], + resolvers: [TransactionResolver, AccountResolver], validate: { validationError: { target: false }, skipMissingProperties: true, diff --git a/dlt-connector/src/graphql/validator/DateString.ts b/dlt-connector/src/graphql/validator/DateString.ts index 3f46d89ec..2be057194 100644 --- a/dlt-connector/src/graphql/validator/DateString.ts +++ b/dlt-connector/src/graphql/validator/DateString.ts @@ -19,3 +19,23 @@ export function isValidDateString(validationOptions?: ValidationOptions) { }) } } + +export function isValidNumberString(validationOptions?: ValidationOptions) { + // eslint-disable-next-line @typescript-eslint/ban-types + return function (object: Object, propertyName: string) { + registerDecorator({ + name: 'isValidNumberString', + target: object.constructor, + propertyName, + options: validationOptions, + validator: { + validate(value: string): boolean { + return !isNaN(parseFloat(value)) + }, + defaultMessage(): string { + return `${propertyName} must be a valid number string` + }, + }, + }) + } +} \ No newline at end of file diff --git a/dlt-connector/src/graphql/validator/Decimal.ts b/dlt-connector/src/graphql/validator/Decimal.ts deleted file mode 100644 index fd2604514..000000000 --- a/dlt-connector/src/graphql/validator/Decimal.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator' -import { Decimal } from 'decimal.js-light' - -export function IsPositiveDecimal(validationOptions?: ValidationOptions) { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (object: Object, propertyName: string) { - registerDecorator({ - name: 'isPositiveDecimal', - target: object.constructor, - propertyName, - options: validationOptions, - validator: { - validate(value: Decimal): boolean { - return value.greaterThan(0) - }, - defaultMessage(args: ValidationArguments): string { - return `The ${propertyName} must be a positive value ${args.property}` - }, - }, - }) - } -} diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index b61157dfb..2dd21b66b 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -7,12 +7,13 @@ import { CONFIG } from '@/config' import { BackendClient } from './client/BackendClient' import { CommunityDraft } from './graphql/input/CommunityDraft' -import { AddCommunityContext } from './interactions/backendToDb/community/AddCommunity.context' import { logger } from './logging/logger' import { KeyPairCacheManager } from './manager/KeyPairCacheManager' import createServer from './server/createServer' import { LogError } from './server/LogError' -import { stopTransmitToIota, transmitToIota } from './tasks/transmitToIota' +import { getTransaction } from './client/GradidoNode' +import { uuid4ToHash } from './utils/typeConverter' +import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' async function waitForServer( backend: BackendClient, @@ -70,11 +71,12 @@ async function main() { const communityDraft = await backend.getHomeCommunityDraft() KeyPairCacheManager.getInstance().setHomeCommunityUUID(communityDraft.uuid) - const addCommunityContext = new AddCommunityContext(communityDraft) - await addCommunityContext.run() - - // loop run all the time, check for new transaction for sending to iota - void transmitToIota() + // ask gradido node if community blockchain was created + const firstTransaction = await getTransaction(1, uuid4ToHash(communityDraft.uuid).convertToHex()) + if (!firstTransaction) { + // if not exist, create community root transaction + await SendToIotaContext(communityDraft) + } app.listen(CONFIG.DLT_CONNECTOR_PORT, () => { // eslint-disable-next-line no-console console.log(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) @@ -82,7 +84,6 @@ async function main() { process.on('exit', () => { // Add shutdown logic here. - stopTransmitToIota() }) } diff --git a/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts b/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts deleted file mode 100644 index c84cb0149..000000000 --- a/dlt-connector/src/interactions/backendToDb/account/RegisterAddress.context.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Account } from '@entity/Account' -import { Transaction } from '@entity/Transaction' -import { User } from '@entity/User' - -import { AccountFactory } from '@/data/Account.factory' -import { CommunityRepository } from '@/data/Community.repository' -import { KeyPair } from '@/data/KeyPair' -import { UserFactory } from '@/data/User.factory' -import { UserLogic } from '@/data/User.logic' -import { UserRepository } from '@/data/User.repository' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' - -import { CreateTransactionRecipeContext } from '../transaction/CreateTransactionRecipe.context' - -export interface TransactionWithAccount { - transaction: Transaction - account: Account -} - -export class RegisterAddressContext { - // eslint-disable-next-line no-useless-constructor - public constructor(private userAccountDraft: UserAccountDraft) {} - - public async run(): Promise { - const community = await CommunityRepository.loadHomeCommunity() - const communityKeyPair = new KeyPair(community) - const user = await this.loadOrCreateUser(communityKeyPair) - if (this.isAccountAlreadyExistOnUser(user)) { - throw new TransactionError( - TransactionErrorType.ALREADY_EXIST, - 'account for this user already exist!', - ) - } - logger.info('add user and account', this.userAccountDraft) - const account = this.createAccount(new UserLogic(user).calculateKeyPair(communityKeyPair)) - account.user = user - const createTransactionContext = new CreateTransactionRecipeContext(this.userAccountDraft, { - community, - account, - }) - await createTransactionContext.run() - return { transaction: createTransactionContext.getTransactionRecipe(), account } - } - - public isAccountAlreadyExistOnUser(user: User): boolean { - return !!user.accounts?.find( - (value) => value.derivationIndex === this.userAccountDraft.user.accountNr, - ) - } - - public async loadOrCreateUser(communityKeyPair: KeyPair): Promise { - let user = await UserRepository.findByGradidoId(this.userAccountDraft.user, { accounts: true }) - if (!user) { - user = UserFactory.create(this.userAccountDraft, communityKeyPair) - } - return user - } - - public createAccount(userKeyPair: KeyPair): Account { - return AccountFactory.createAccountFromUserAccountDraft(this.userAccountDraft, userKeyPair) - } -} diff --git a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.test.ts b/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.test.ts deleted file mode 100644 index d7ec4e9c6..000000000 --- a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import 'reflect-metadata' -import { Community } from '@entity/Community' - -import { TestDB } from '@test/TestDB' - -import { CONFIG } from '@/config' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' - -import { AddCommunityContext } from './AddCommunity.context' - -CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa73546bd5f5bf0b71285' - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -describe('interactions/backendToDb/community/AddCommunity Context Test', () => { - beforeAll(async () => { - await TestDB.instance.setupTestDB() - }) - - afterAll(async () => { - await TestDB.instance.teardownTestDB() - }) - - const homeCommunityDraft = new CommunityDraft() - homeCommunityDraft.uuid = 'a2fd0fee-f3ba-4bef-a62a-10a34b0e2754' - homeCommunityDraft.foreign = false - homeCommunityDraft.createdAt = '2024-01-25T13:09:55.339Z' - // calculated from a2fd0fee-f3ba-4bef-a62a-10a34b0e2754 with iotaTopicFromCommunityUUID - const iotaTopic = '7be2ad83f279a3aaf6d62371cb6be301e2e3c7a3efda9c89984e8f6a7865d9ce' - - const foreignCommunityDraft = new CommunityDraft() - foreignCommunityDraft.uuid = '70df8de5-0fb7-4153-a124-4ff86965be9a' - foreignCommunityDraft.foreign = true - foreignCommunityDraft.createdAt = '2024-01-25T13:34:28.020Z' - - it('with home community, without iota topic', async () => { - const context = new AddCommunityContext(homeCommunityDraft) - await context.run() - const homeCommunity = await Community.findOneOrFail({ where: { iotaTopic } }) - expect(homeCommunity).toMatchObject({ - id: 1, - iotaTopic, - foreign: 0, - rootPubkey: Buffer.from( - '07cbf56d4b6b7b188c5f6250c0f4a01d0e44e1d422db1935eb375319ad9f9af0', - 'hex', - ), - createdAt: new Date('2024-01-25T13:09:55.339Z'), - }) - }) - - it('with foreign community', async () => { - const context = new AddCommunityContext(foreignCommunityDraft, 'randomTopic') - await context.run() - const foreignCommunity = await Community.findOneOrFail({ where: { foreign: true } }) - expect(foreignCommunity).toMatchObject({ - id: 2, - iotaTopic: 'randomTopic', - foreign: 1, - createdAt: new Date('2024-01-25T13:34:28.020Z'), - }) - }) -}) diff --git a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts b/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts deleted file mode 100644 index 16bfd8513..000000000 --- a/dlt-connector/src/interactions/backendToDb/community/AddCommunity.context.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { uuid4ToHash } from '@/utils/typeConverter' - -import { CommunityRole } from './Community.role' -import { ForeignCommunityRole } from './ForeignCommunity.role' -import { HomeCommunityRole } from './HomeCommunity.role' - -/** - * @DCI-Context - * Context for adding community to DB - * using roles to distinct between foreign and home communities - */ -export class AddCommunityContext { - private communityRole: CommunityRole - private iotaTopic: string - public constructor(private communityDraft: CommunityDraft, iotaTopic?: string) { - if (!iotaTopic) { - this.iotaTopic = uuid4ToHash(this.communityDraft.uuid) - } else { - this.iotaTopic = iotaTopic - } - this.communityRole = communityDraft.foreign - ? new ForeignCommunityRole() - : new HomeCommunityRole() - } - - public async run(): Promise { - await this.communityRole.create(this.communityDraft, this.iotaTopic) - await this.communityRole.store() - } -} diff --git a/dlt-connector/src/interactions/backendToDb/community/Community.role.ts b/dlt-connector/src/interactions/backendToDb/community/Community.role.ts deleted file mode 100644 index 2b1514ef2..000000000 --- a/dlt-connector/src/interactions/backendToDb/community/Community.role.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Community } from '@entity/Community' - -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { CommunityLoggingView } from '@/logging/CommunityLogging.view' -import { logger } from '@/logging/logger' - -export abstract class CommunityRole { - protected self: Community - public constructor() { - this.self = Community.create() - } - - public async create(communityDraft: CommunityDraft, topic: string): Promise { - this.self.iotaTopic = topic - this.self.createdAt = new Date(communityDraft.createdAt) - this.self.foreign = communityDraft.foreign - } - - public async store(): Promise { - try { - const community = await this.self.save() - logger.debug('store community', new CommunityLoggingView(community)) - return community - } catch (error) { - logger.error('error saving new community into db: %s', error) - throw new TransactionError(TransactionErrorType.DB_ERROR, 'error saving community into db') - } - } -} diff --git a/dlt-connector/src/interactions/backendToDb/community/ForeignCommunity.role.ts b/dlt-connector/src/interactions/backendToDb/community/ForeignCommunity.role.ts deleted file mode 100644 index cf93deaa5..000000000 --- a/dlt-connector/src/interactions/backendToDb/community/ForeignCommunity.role.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { CommunityRole } from './Community.role' - -// same as base class -export class ForeignCommunityRole extends CommunityRole {} diff --git a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts b/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts deleted file mode 100644 index 050b245e3..000000000 --- a/dlt-connector/src/interactions/backendToDb/community/HomeCommunity.role.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' - -import { CONFIG } from '@/config' -import { AccountFactory } from '@/data/Account.factory' -import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' -import { KeyPair } from '@/data/KeyPair' -import { Mnemonic } from '@/data/Mnemonic' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { CommunityLoggingView } from '@/logging/CommunityLogging.view' -import { logger } from '@/logging/logger' -import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' -import { LogError } from '@/server/LogError' -import { getDataSource } from '@/typeorm/DataSource' - -import { CreateTransactionRecipeContext } from '../transaction/CreateTransactionRecipe.context' - -import { CommunityRole } from './Community.role' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' - -export class HomeCommunityRole extends CommunityRole { - private transactionRecipe: Transaction - - public async create(communityDraft: CommunityDraft, topic: string): Promise { - super.create(communityDraft, topic) - // generate key pair for signing transactions and deriving all keys for community - let mnemonic: Mnemonic - try { - mnemonic = new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED ?? undefined) - } catch (e) { - throw new LogError( - 'error creating mnemonic for home community, please fill IOTA_HOME_COMMUNITY_SEED in .env', - { - IOTA_HOME_COMMUNITY_SEED: CONFIG.IOTA_HOME_COMMUNITY_SEED, - error: e, - }, - ) - } - const keyPair = new KeyPair(mnemonic) - keyPair.fillInCommunityKeys(this.self) - - // create auf account and gmw account - this.self.aufAccount = AccountFactory.createAufAccount(keyPair, this.self.createdAt) - this.self.gmwAccount = AccountFactory.createGmwAccount(keyPair, this.self.createdAt) - - const transactionRecipeContext = new CreateTransactionRecipeContext(communityDraft, { - community: this.self, - }) - await transactionRecipeContext.run() - this.transactionRecipe = transactionRecipeContext.getTransactionRecipe() - } - - public async store(): Promise { - try { - const community = await getDataSource().transaction(async (transactionalEntityManager) => { - const community = await transactionalEntityManager.save(this.self) - await transactionalEntityManager.save(this.transactionRecipe) - logger.debug('store home community', new CommunityLoggingView(community)) - return community - }) - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - return community - } catch (error) { - logger.error('error saving home community into db: %s', error) - throw new TransactionError( - TransactionErrorType.DB_ERROR, - 'error saving home community into db', - ) - } - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts deleted file mode 100644 index 2b815cd7a..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransaction.role.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable camelcase */ -import { Account } from '@entity/Account' -import { GradidoTransactionBuilder } from 'gradido-blockchain-js' - -import { UserRepository } from '@/data/User.repository' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { TransactionError } from '@/graphql/model/TransactionError' - -export abstract class AbstractTransactionRole { - // eslint-disable-next-line no-useless-constructor - public constructor(protected self: TransactionDraft) {} - - abstract getSigningUser(): UserIdentifier - abstract getRecipientUser(): UserIdentifier - abstract getGradidoTransactionBuilder(): Promise - - public isCrossGroupTransaction(): boolean { - return ( - this.self.user.communityUuid !== this.self.linkedUser.communityUuid && - this.self.linkedUser.communityUuid !== '' - ) - } - - public async loadUser(user: UserIdentifier): Promise { - const account = await UserRepository.findAccountByUserIdentifier(user) - if (!account) { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, - "couldn't found user account in db", - ) - } - return account - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts b/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts deleted file mode 100644 index 812f6a7f0..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/AbstractTransactionRecipeRole.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Transaction } from '@entity/Transaction' - -import { TransactionBuilder } from '@/data/Transaction.builder' - -export class AbstractTransactionRecipeRole { - protected transactionBuilder: TransactionBuilder - - public constructor() { - this.transactionBuilder = new TransactionBuilder() - } - - public getTransaction(): Transaction { - return this.transactionBuilder.getTransaction() - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts b/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts deleted file mode 100644 index 659c62c22..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/BalanceChangingTransactionRecipeRole.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable camelcase */ -import { AccountLogic } from '@/data/Account.logic' -import { KeyPair } from '@/data/KeyPair' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' - -import { AbstractTransactionRole } from './AbstractTransaction.role' -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' - -export class BalanceChangingTransactionRecipeRole extends AbstractTransactionRecipeRole { - public async create( - transactionDraft: TransactionDraft, - transactionTypeRole: AbstractTransactionRole, - ): Promise { - // loading signing and recipient account - const signingAccount = await transactionTypeRole.loadUser(transactionTypeRole.getSigningUser()) - const recipientAccount = await transactionTypeRole.loadUser( - transactionTypeRole.getRecipientUser(), - ) - const accountLogic = new AccountLogic(signingAccount) - await this.transactionBuilder.setCommunityFromUser(transactionDraft.user) - const communityKeyPair = new KeyPair(this.transactionBuilder.getCommunity()) - - const gradidoTransactionBuilder = await transactionTypeRole.getGradidoTransactionBuilder() - const transaction = gradidoTransactionBuilder - .setCreatedAt(new Date(transactionDraft.createdAt)) - .sign(accountLogic.calculateKeyPair(communityKeyPair).keyPair) - .build() - - // build transaction entity - this.transactionBuilder - .fromGradidoTransaction(transaction) - .setRecipientAccount(recipientAccount) - .setSigningAccount(signingAccount) - - if (transactionTypeRole.isCrossGroupTransaction()) { - await this.transactionBuilder.setOtherCommunityFromUser(transactionDraft.linkedUser) - } - return this - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts deleted file mode 100644 index cdd953d4c..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/CommunityRootTransaction.role.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Community } from '@entity/Community' -// eslint-disable-next-line camelcase -import { MemoryBlock, GradidoTransactionBuilder } from 'gradido-blockchain-js' - -import { KeyPair } from '@/data/KeyPair' -// import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' - -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' - -export class CommunityRootTransactionRole extends AbstractTransactionRecipeRole { - public create( - communityDraft: CommunityDraft, - community: Community, - ): AbstractTransactionRecipeRole { - if ( - !community.rootPubkey || - !community.gmwAccount?.derive2Pubkey || - !community.aufAccount?.derive2Pubkey - ) { - throw new Error('missing one of the public keys for community') - } - // create proto transaction body - const transaction = new GradidoTransactionBuilder() - .setCommunityRoot( - new MemoryBlock(community.rootPubkey), - new MemoryBlock(community.gmwAccount?.derive2Pubkey), - new MemoryBlock(community.aufAccount?.derive2Pubkey), - ) - .setCreatedAt(new Date(communityDraft.createdAt)) - .sign(new KeyPair(community).keyPair) - .build() - - // build transaction entity - this.transactionBuilder.fromGradidoTransaction(transaction).setCommunity(community) - return this - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts deleted file mode 100644 index 6671e6e78..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.test.ts +++ /dev/null @@ -1,420 +0,0 @@ -/* eslint-disable camelcase */ -import 'reflect-metadata' -import { Account } from '@entity/Account' -import { Community } from '@entity/Community' -import { - AddressType_COMMUNITY_HUMAN, - CrossGroupType_INBOUND, - CrossGroupType_LOCAL, - CrossGroupType_OUTBOUND, - InteractionDeserialize, - MemoryBlock, - TransactionType_CREATION, -} from 'gradido-blockchain-js' -import { v4 } from 'uuid' - -import { TestDB } from '@test/TestDB' - -import { CONFIG } from '@/config' -import { KeyPair } from '@/data/KeyPair' -import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' -import { AccountType } from '@/graphql/enum/AccountType' -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { uuid4ToHash } from '@/utils/typeConverter' - -import { CreateTransactionRecipeContext } from './CreateTransactionRecipe.context' - -// eslint-disable-next-line import/order -import { communitySeed } from '@test/seeding/Community.seed' -// eslint-disable-next-line import/order -import { createUserSet, UserSet } from '@test/seeding/UserSet.seed' - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa73546bd5f5bf0b71285' -const homeCommunityUuid = v4() -const foreignCommunityUuid = v4() - -const keyPair = new KeyPair(MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED)) -const foreignKeyPair = new KeyPair( - MemoryBlock.fromHex('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'), -) - -let moderator: UserSet -let firstUser: UserSet -let secondUser: UserSet -let foreignUser: UserSet -let homeCommunity: Community - -const topic = uuid4ToHash(homeCommunityUuid) -const foreignTopic = uuid4ToHash(foreignCommunityUuid) - -describe('interactions/backendToDb/transaction/Create Transaction Recipe Context Test', () => { - beforeAll(async () => { - await TestDB.instance.setupTestDB() - homeCommunity = await communitySeed(homeCommunityUuid, false) - await communitySeed(foreignCommunityUuid, true, foreignKeyPair) - - moderator = createUserSet(homeCommunityUuid, keyPair) - firstUser = createUserSet(homeCommunityUuid, keyPair) - secondUser = createUserSet(homeCommunityUuid, keyPair) - foreignUser = createUserSet(foreignCommunityUuid, foreignKeyPair) - - await Account.save([ - moderator.account, - firstUser.account, - secondUser.account, - foreignUser.account, - ]) - }) - - afterAll(async () => { - await TestDB.instance.teardownTestDB() - }) - - it('register address transaction', async () => { - const userAccountDraft = new UserAccountDraft() - userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN - userAccountDraft.createdAt = new Date().toISOString() - userAccountDraft.user = firstUser.identifier - const context = new CreateTransactionRecipeContext(userAccountDraft, { - account: firstUser.account, - community: homeCommunity, - }) - await context.run() - const transaction = context.getTransactionRecipe() - expect(transaction).toMatchObject({ - type: TransactionType.REGISTER_ADDRESS, - protocolVersion: '3.3', - community: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - signingAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - }) - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - expect(body?.isRegisterAddress()).toBeTruthy() - - expect(body).toMatchObject({ - type: CrossGroupType_LOCAL, - registerAddress: { - derivationIndex: 1, - addressType: AddressType_COMMUNITY_HUMAN, - }, - }) - }) - - it('creation transaction', async () => { - const creationTransactionDraft = new TransactionDraft() - creationTransactionDraft.amount = new Decimal('2000') - creationTransactionDraft.backendTransactionId = 1 - creationTransactionDraft.createdAt = new Date().toISOString() - creationTransactionDraft.linkedUser = moderator.identifier - creationTransactionDraft.user = firstUser.identifier - creationTransactionDraft.type = InputTransactionType.CREATION - creationTransactionDraft.targetDate = new Date().toISOString() - const context = new CreateTransactionRecipeContext(creationTransactionDraft) - await context.run() - const transaction = context.getTransactionRecipe() - - expect(transaction).toMatchObject({ - type: TransactionType_CREATION, - protocolVersion: '3.3', - community: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - signingAccount: { - derive2Pubkey: moderator.account.derive2Pubkey, - }, - recipientAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - amount: new Decimal(2000), - backendTransactions: [ - { - typeId: InputTransactionType.CREATION, - }, - ], - }) - - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - // console.log(new TransactionBodyLoggingView(body)) - expect(body?.isCreation()).toBeTruthy() - - expect( - body - ?.getCreation() - ?.getRecipient() - .getPubkey() - ?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), - ).toBeTruthy() - - expect(body).toMatchObject({ - type: CrossGroupType_LOCAL, - creation: { - recipient: { - amount: '2000', - }, - }, - }) - }) - - it('local send transaction', async () => { - const sendTransactionDraft = new TransactionDraft() - sendTransactionDraft.amount = new Decimal('100') - sendTransactionDraft.backendTransactionId = 2 - sendTransactionDraft.createdAt = new Date().toISOString() - sendTransactionDraft.linkedUser = secondUser.identifier - sendTransactionDraft.user = firstUser.identifier - sendTransactionDraft.type = InputTransactionType.SEND - const context = new CreateTransactionRecipeContext(sendTransactionDraft) - await context.run() - const transaction = context.getTransactionRecipe() - - // console.log(new TransactionLoggingView(transaction)) - expect(transaction).toMatchObject({ - type: TransactionType.GRADIDO_TRANSFER, - protocolVersion: '3.3', - community: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - signingAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - recipientAccount: { - derive2Pubkey: secondUser.account.derive2Pubkey, - }, - amount: new Decimal(100), - backendTransactions: [ - { - typeId: InputTransactionType.SEND, - }, - ], - }) - - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - // console.log(new TransactionBodyLoggingView(body)) - expect(body?.isTransfer()).toBeTruthy() - const transfer = body?.getTransfer() - expect(transfer).not.toBeNull() - expect( - transfer?.getRecipient()?.equal(new MemoryBlock(secondUser.account.derive2Pubkey)), - ).toBeTruthy() - expect( - transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), - ).toBeTruthy() - - expect(body).toMatchObject({ - type: CrossGroupType_LOCAL, - transfer: { - sender: { - amount: '100', - }, - }, - }) - }) - - it('local recv transaction', async () => { - const recvTransactionDraft = new TransactionDraft() - recvTransactionDraft.amount = new Decimal('100') - recvTransactionDraft.backendTransactionId = 3 - recvTransactionDraft.createdAt = new Date().toISOString() - recvTransactionDraft.linkedUser = firstUser.identifier - recvTransactionDraft.user = secondUser.identifier - recvTransactionDraft.type = InputTransactionType.RECEIVE - const context = new CreateTransactionRecipeContext(recvTransactionDraft) - await context.run() - const transaction = context.getTransactionRecipe() - // console.log(new TransactionLoggingView(transaction)) - expect(transaction).toMatchObject({ - type: TransactionType.GRADIDO_TRANSFER, - protocolVersion: '3.3', - community: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - signingAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - recipientAccount: { - derive2Pubkey: secondUser.account.derive2Pubkey, - }, - amount: new Decimal(100), - backendTransactions: [ - { - typeId: InputTransactionType.RECEIVE, - }, - ], - }) - - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - expect(body?.isTransfer()).toBeTruthy() - const transfer = body?.getTransfer() - expect(transfer).not.toBeNull() - expect( - transfer?.getRecipient()?.equal(new MemoryBlock(secondUser.account.derive2Pubkey)), - ).toBeTruthy() - expect( - transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), - ).toBeTruthy() - - expect(body).toMatchObject({ - type: CrossGroupType_LOCAL, - transfer: { - sender: { - amount: '100', - }, - }, - }) - }) - - it('cross group send transaction', async () => { - const crossGroupSendTransactionDraft = new TransactionDraft() - crossGroupSendTransactionDraft.amount = new Decimal('100') - crossGroupSendTransactionDraft.backendTransactionId = 4 - crossGroupSendTransactionDraft.createdAt = new Date().toISOString() - crossGroupSendTransactionDraft.linkedUser = foreignUser.identifier - crossGroupSendTransactionDraft.user = firstUser.identifier - crossGroupSendTransactionDraft.type = InputTransactionType.SEND - const context = new CreateTransactionRecipeContext(crossGroupSendTransactionDraft) - await context.run() - const transaction = context.getTransactionRecipe() - // console.log(new TransactionLoggingView(transaction)) - expect(transaction).toMatchObject({ - type: TransactionType.GRADIDO_TRANSFER, - protocolVersion: '3.3', - community: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - otherCommunity: { - rootPubkey: foreignKeyPair.publicKey, - foreign: 1, - iotaTopic: foreignTopic, - }, - signingAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - recipientAccount: { - derive2Pubkey: foreignUser.account.derive2Pubkey, - }, - amount: new Decimal(100), - backendTransactions: [ - { - typeId: InputTransactionType.SEND, - }, - ], - }) - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - // console.log(new TransactionBodyLoggingView(body)) - expect(body?.isTransfer()).toBeTruthy() - const transfer = body?.getTransfer() - expect(transfer).not.toBeNull() - expect( - transfer?.getRecipient()?.equal(new MemoryBlock(foreignUser.account.derive2Pubkey)), - ).toBeTruthy() - expect( - transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), - ).toBeTruthy() - expect(body).toMatchObject({ - type: CrossGroupType_OUTBOUND, - otherGroup: foreignTopic, - transfer: { - sender: { - amount: '100', - }, - }, - }) - }) - - it('cross group recv transaction', async () => { - const crossGroupRecvTransactionDraft = new TransactionDraft() - crossGroupRecvTransactionDraft.amount = new Decimal('100') - crossGroupRecvTransactionDraft.backendTransactionId = 5 - crossGroupRecvTransactionDraft.createdAt = new Date().toISOString() - crossGroupRecvTransactionDraft.linkedUser = firstUser.identifier - crossGroupRecvTransactionDraft.user = foreignUser.identifier - crossGroupRecvTransactionDraft.type = InputTransactionType.RECEIVE - const context = new CreateTransactionRecipeContext(crossGroupRecvTransactionDraft) - await context.run() - const transaction = context.getTransactionRecipe() - // console.log(new TransactionLoggingView(transaction)) - expect(transaction).toMatchObject({ - type: TransactionType.GRADIDO_TRANSFER, - protocolVersion: '3.3', - community: { - rootPubkey: foreignKeyPair.publicKey, - foreign: 1, - iotaTopic: foreignTopic, - }, - otherCommunity: { - rootPubkey: keyPair.publicKey, - foreign: 0, - iotaTopic: topic, - }, - signingAccount: { - derive2Pubkey: firstUser.account.derive2Pubkey, - }, - recipientAccount: { - derive2Pubkey: foreignUser.account.derive2Pubkey, - }, - amount: new Decimal(100), - backendTransactions: [ - { - typeId: InputTransactionType.RECEIVE, - }, - ], - }) - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - // console.log(new TransactionBodyLoggingView(body)) - expect(body?.isTransfer()).toBeTruthy() - const transfer = body?.getTransfer() - expect(transfer).not.toBeNull() - expect( - transfer?.getRecipient()?.equal(new MemoryBlock(foreignUser.account.derive2Pubkey)), - ).toBeTruthy() - expect( - transfer?.getSender().getPubkey()?.equal(new MemoryBlock(firstUser.account.derive2Pubkey)), - ).toBeTruthy() - expect(body).toMatchObject({ - type: CrossGroupType_INBOUND, - otherGroup: topic, - transfer: { - sender: { - amount: '100', - }, - }, - }) - }) -}) diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts deleted file mode 100644 index 10bb3f4f6..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreateTransactionRecipe.context.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Account } from '@entity/Account' -import { Community } from '@entity/Community' -import { Transaction } from '@entity/Transaction' - -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - -import { AbstractTransactionRole } from './AbstractTransaction.role' -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' -import { BalanceChangingTransactionRecipeRole } from './BalanceChangingTransactionRecipeRole' -import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' -import { CreationTransactionRole } from './CreationTransaction.role' -import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' -import { SendTransactionRole } from './SendTransaction.role' - -/** - * @DCI-Context - * Context for create and add Transaction Recipe to DB - */ - -export interface AdditionalData { - community?: Community - account?: Account -} - -export class CreateTransactionRecipeContext { - private transactionRecipe: AbstractTransactionRecipeRole - // eslint-disable-next-line no-useless-constructor - public constructor( - private draft: CommunityDraft | TransactionDraft | UserAccountDraft, - private data?: AdditionalData, - ) {} - - public getTransactionRecipe(): Transaction { - return this.transactionRecipe.getTransaction() - } - - /** - * @returns true if a transaction recipe was created and false if it wasn't necessary - */ - public async run(): Promise { - if (this.draft instanceof TransactionDraft) { - // contain logic for translation from backend to dlt-connector format - let transactionTypeRole: AbstractTransactionRole - switch (this.draft.type) { - case InputTransactionType.CREATION: - transactionTypeRole = new CreationTransactionRole(this.draft) - break - case InputTransactionType.SEND: - transactionTypeRole = new SendTransactionRole(this.draft) - break - case InputTransactionType.RECEIVE: - return false - } - this.transactionRecipe = await new BalanceChangingTransactionRecipeRole().create( - this.draft, - transactionTypeRole, - ) - return true - } else if (this.draft instanceof CommunityDraft) { - if (!this.data?.community) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community was not set') - } - this.transactionRecipe = new CommunityRootTransactionRole().create( - this.draft, - this.data.community, - ) - return true - } else if (this.draft instanceof UserAccountDraft) { - if (!this.data?.account) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'account was not set') - } - if (!this.data.community) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community was not set') - } - this.transactionRecipe = await new RegisterAddressTransactionRole().create( - this.draft, - this.data.account, - this.data.community, - ) - return true - } - return false - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts deleted file mode 100644 index 40648b566..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/CreationTransaction.role.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* eslint-disable camelcase */ -import { Community } from '@entity/Community' -import { MemoryBlock, GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' - -import { CommunityRepository } from '@/data/Community.repository' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' -import { UserIdentifierLoggingView } from '@/logging/UserIdentifierLogging.view' - -import { AbstractTransactionRole } from './AbstractTransaction.role' - -export class CreationTransactionRole extends AbstractTransactionRole { - public getSigningUser(): UserIdentifier { - return this.self.linkedUser - } - - public getRecipientUser(): UserIdentifier { - return this.self.user - } - - public async getGradidoTransactionBuilder(): Promise { - const builder = new GradidoTransactionBuilder() - const recipientUser = await this.loadUser(this.self.user) - if (!this.self.targetDate) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing targetDate for contribution', - ) - } - return builder - .setTransactionCreation( - new TransferAmount( - new MemoryBlock(recipientUser.derive2Pubkey), - this.self.amount.toString(), - ), - new Date(this.self.targetDate), - ) - .setMemo('dummy memo for creation') - } - - public async getCommunity(): Promise { - if (this.self.user.communityUuid !== this.self.linkedUser.communityUuid) { - throw new TransactionError( - TransactionErrorType.LOGIC_ERROR, - 'mismatch community uuids on contribution', - ) - } - const community = await CommunityRepository.getCommunityForUserIdentifier(this.self.user) - if (!community) { - logger.error( - 'missing community for user identifier', - new UserIdentifierLoggingView(this.self.user), - ) - throw new TransactionError(TransactionErrorType.NOT_FOUND, "couldn't find community for user") - } - return community - } - - public async getOtherCommunity(): Promise { - return null - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts deleted file mode 100644 index f2a41a72f..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/RegisterAddressTransaction.role.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Account } from '@entity/Account' -import { Community } from '@entity/Community' -import { - // eslint-disable-next-line camelcase - AddressType_COMMUNITY_HUMAN, - MemoryBlock, - GradidoTransactionBuilder, -} from 'gradido-blockchain-js' - -import { AccountLogic } from '@/data/Account.logic' -import { CommunityRepository } from '@/data/Community.repository' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipeRole' - -export class RegisterAddressTransactionRole extends AbstractTransactionRecipeRole { - async create( - userAccountDraft: UserAccountDraft, - account: Account, - community: Community, - ): Promise { - const user = account.user - if (!user) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'missing user for account') - } - const gradidoTransactionBuilder = new GradidoTransactionBuilder() - const communityKeyPair = await CommunityRepository.loadHomeCommunityKeyPair() - const signingKeyPair = new AccountLogic(account).calculateKeyPair(communityKeyPair) - if (!signingKeyPair) { - throw new TransactionError(TransactionErrorType.NOT_FOUND, "couldn't found signing key pair") - } - const transaction = gradidoTransactionBuilder - .setRegisterAddress( - new MemoryBlock(user.derive1Pubkey), - AddressType_COMMUNITY_HUMAN, - null, - new MemoryBlock(account.derive2Pubkey), - ) - .setCreatedAt(new Date(userAccountDraft.createdAt)) - .sign(signingKeyPair.keyPair) - .sign(communityKeyPair.keyPair) - .build() - - this.transactionBuilder - .fromGradidoTransaction(transaction) - .setCommunity(community) - .setSigningAccount(account) - return this - } -} diff --git a/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts b/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts deleted file mode 100644 index 874656cda..000000000 --- a/dlt-connector/src/interactions/backendToDb/transaction/SendTransaction.role.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-disable camelcase */ -import { - CrossGroupType, - CrossGroupType_LOCAL, - CrossGroupType_OUTBOUND, - MemoryBlock, - GradidoTransactionBuilder, - TransferAmount, -} from 'gradido-blockchain-js' - -import { UserIdentifier } from '@/graphql/input/UserIdentifier' - -import { AbstractTransactionRole } from './AbstractTransaction.role' - -export class SendTransactionRole extends AbstractTransactionRole { - public getSigningUser(): UserIdentifier { - return this.self.user - } - - public getRecipientUser(): UserIdentifier { - return this.self.linkedUser - } - - public async getGradidoTransactionBuilder(): Promise { - const builder = new GradidoTransactionBuilder() - const signingUser = await this.loadUser(this.self.user) - const recipientUser = await this.loadUser(this.self.linkedUser) - return builder - .setTransactionTransfer( - new TransferAmount(new MemoryBlock(signingUser.derive2Pubkey), this.self.amount.toString()), - new MemoryBlock(recipientUser.derive2Pubkey), - ) - .setMemo('dummy memo for transfer') - } -} diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts index 498e71bf7..dc80d7c02 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -1,9 +1,9 @@ /* eslint-disable camelcase */ -import { AddressType_COMMUNITY_HUMAN, GradidoTransactionBuilder } from 'gradido-blockchain-js' +import { GradidoTransactionBuilder } from 'gradido-blockchain-js' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' +import { accountTypeToAddressType, uuid4ToHash } from '@/utils/typeConverter' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -30,7 +30,7 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { .setCreatedAt(new Date(this.self.createdAt)) .setRegisterAddress( accountKeyPair.getPublicKey(), - AddressType_COMMUNITY_HUMAN, + accountTypeToAddressType(this.self.accountType), uuid4ToHash(this.self.user.uuid), ) .sign(communityKeyPair) diff --git a/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts deleted file mode 100644 index e8730f8e3..000000000 --- a/dlt-connector/src/interactions/transmitToIota/AbstractTransactionRecipe.role.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* eslint-disable camelcase */ -import { Transaction } from '@entity/Transaction' -import { - GradidoTransaction, - GradidoTransactionBuilder, - InteractionSerialize, - InteractionValidate, - MemoryBlock, - TransactionType_COMMUNITY_ROOT, - ValidateType_SINGLE, -} from 'gradido-blockchain-js' - -import { sendMessage as iotaSendMessage } from '@/client/IotaClient' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' - -export abstract class AbstractTransactionRecipeRole { - // eslint-disable-next-line no-useless-constructor - public constructor(protected self: Transaction) {} - - public abstract transmitToIota(): Promise - public abstract getCrossGroupTypeName(): string - - public validate(transactionBuilder: GradidoTransactionBuilder): GradidoTransaction { - const transaction = transactionBuilder.build() - try { - // throw an exception when something is wrong - const validator = new InteractionValidate(transaction) - validator.run(ValidateType_SINGLE) - } catch (e) { - if (e instanceof Error) { - throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e.message) - } else if (typeof e === 'string') { - throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e) - } else { - throw e - } - } - return transaction - } - - protected getGradidoTransactionBuilder(): GradidoTransactionBuilder { - if (!this.self.signature) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing signature in transaction recipe', - ) - } - let publicKey: Buffer | undefined - if (this.self.type === TransactionType_COMMUNITY_ROOT) { - publicKey = this.self.community.rootPubkey - if (!publicKey) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing community public key for community root transaction', - ) - } - } else if (this.self.signingAccount) { - publicKey = this.self.signingAccount.derive2Pubkey - if (!publicKey) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'missing signing account public key for transaction', - ) - } - } else { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, - "signingAccount not exist and it isn't a community root transaction", - ) - } - return new GradidoTransactionBuilder() - .setTransactionBody(new MemoryBlock(this.self.bodyBytes)) - .addSignaturePair(new MemoryBlock(publicKey), new MemoryBlock(this.self.signature)) - } - - /** - * - * @param gradidoTransaction - * @param topic - * @return iota message id - */ - protected async sendViaIota( - gradidoTransaction: GradidoTransaction, - topic: string, - ): Promise { - // protobuf serializing function - const serialized = new InteractionSerialize(gradidoTransaction).run() - if (!serialized) { - throw new TransactionError( - TransactionErrorType.PROTO_ENCODE_ERROR, - 'cannot serialize transaction', - ) - } - const resultMessage = await iotaSendMessage( - Uint8Array.from(serialized.data()), - Uint8Array.from(Buffer.from(topic, 'hex')), - ) - logger.info('transmitted Gradido Transaction to Iota', { - id: this.self.id, - messageId: resultMessage.messageId, - }) - return Buffer.from(resultMessage.messageId, 'hex') - } -} diff --git a/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts deleted file mode 100644 index afa171a37..000000000 --- a/dlt-connector/src/interactions/transmitToIota/InboundTransactionRecipe.role.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Transaction } from '@entity/Transaction' -import { MemoryBlock } from 'gradido-blockchain-js' - -import { logger } from '@/logging/logger' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' -import { LogError } from '@/server/LogError' - -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role' - -/** - * Inbound Transaction on recipient community, mark the gradidos as received from another community - * need to set gradido id from OUTBOUND transaction! - */ -export class InboundTransactionRecipeRole extends AbstractTransactionRecipeRole { - public getCrossGroupTypeName(): string { - return 'INBOUND' - } - - public async transmitToIota(): Promise { - logger.debug('transmit INBOUND transaction to iota', new TransactionLoggingView(this.self)) - const builder = this.getGradidoTransactionBuilder() - const pairingTransaction = await new TransactionLogic(this.self).findPairTransaction() - if (!pairingTransaction.iotaMessageId || pairingTransaction.iotaMessageId.length !== 32) { - throw new LogError( - 'missing iota message id in pairing transaction, was it already send?', - new TransactionLoggingView(pairingTransaction), - ) - } - builder.setParentMessageId(new MemoryBlock(pairingTransaction.iotaMessageId)) - this.self.pairingTransactionId = pairingTransaction.id - this.self.pairingTransaction = pairingTransaction - pairingTransaction.pairingTransactionId = this.self.id - - if (!this.self.otherCommunity) { - throw new LogError('missing other community') - } - - this.self.iotaMessageId = await this.sendViaIota( - this.validate(builder), - this.self.otherCommunity.iotaTopic, - ) - return this.self - } -} diff --git a/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts b/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts deleted file mode 100644 index 10f862d9a..000000000 --- a/dlt-connector/src/interactions/transmitToIota/LocalTransactionRecipe.role.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Transaction } from '@entity/Transaction' - -import { logger } from '@/logging/logger' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' - -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role' - -export class LocalTransactionRecipeRole extends AbstractTransactionRecipeRole { - public getCrossGroupTypeName(): string { - return 'LOCAL' - } - - public async transmitToIota(): Promise { - logger.debug( - `transmit ${this.getCrossGroupTypeName()} transaction to iota`, - new TransactionLoggingView(this.self), - ) - this.self.iotaMessageId = await this.sendViaIota( - this.validate(this.getGradidoTransactionBuilder()), - this.self.community.iotaTopic, - ) - return this.self - } -} diff --git a/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts b/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts deleted file mode 100644 index d3b0b67c4..000000000 --- a/dlt-connector/src/interactions/transmitToIota/OutboundTransactionRecipeRole.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LocalTransactionRecipeRole } from './LocalTransactionRecipe.role' - -/** - * Outbound Transaction on sender community, mark the gradidos as sended out of community - */ -export class OutboundTransactionRecipeRole extends LocalTransactionRecipeRole { - public getCrossGroupTypeName(): string { - return 'OUTBOUND' - } -} diff --git a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts deleted file mode 100644 index f366be2b4..000000000 --- a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -import 'reflect-metadata' -import { Account } from '@entity/Account' -import { Decimal } from 'decimal.js-light' -import { CrossGroupType_INBOUND, CrossGroupType_OUTBOUND, InteractionDeserialize, InteractionToJson, InteractionValidate, MemoryBlock } from 'gradido-blockchain-js' -import { v4 } from 'uuid' - -import { TestDB } from '@test/TestDB' - -import { CONFIG } from '@/config' -import { KeyPair } from '@/data/KeyPair' -import { Mnemonic } from '@/data/Mnemonic' -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { logger } from '@/logging/logger' - -import { CreateTransactionRecipeContext } from '../backendToDb/transaction/CreateTransactionRecipe.context' - -import { TransmitToIotaContext } from './TransmitToIota.context' - -// eslint-disable-next-line import/order -import { communitySeed } from '@test/seeding/Community.seed' -// eslint-disable-next-line import/order -import { createUserSet, UserSet } from '@test/seeding/UserSet.seed' - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -jest.mock('@/client/IotaClient', () => { - return { - sendMessage: jest.fn().mockReturnValue({ - messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', - }), - } -}) - -CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa73546bd5f5bf0b71285' -const homeCommunityUuid = v4() -const foreignCommunityUuid = v4() - -const keyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED)) -const foreignKeyPair = new KeyPair( - new Mnemonic('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'), -) - -let moderator: UserSet -let firstUser: UserSet -let secondUser: UserSet -let foreignUser: UserSet - -const now = new Date() - -describe('interactions/transmitToIota/TransmitToIotaContext', () => { - beforeAll(async () => { - await TestDB.instance.setupTestDB() - await communitySeed(homeCommunityUuid, false) - await communitySeed(foreignCommunityUuid, true, foreignKeyPair) - - moderator = createUserSet(homeCommunityUuid, keyPair) - firstUser = createUserSet(homeCommunityUuid, keyPair) - secondUser = createUserSet(homeCommunityUuid, keyPair) - foreignUser = createUserSet(foreignCommunityUuid, foreignKeyPair) - - await Account.save([ - moderator.account, - firstUser.account, - secondUser.account, - foreignUser.account, - ]) - }) - - afterAll(async () => { - await TestDB.instance.teardownTestDB() - }) - - it('LOCAL transaction', async () => { - const creationTransactionDraft = new TransactionDraft() - creationTransactionDraft.amount = new Decimal('1000') - creationTransactionDraft.backendTransactionId = 1 - creationTransactionDraft.createdAt = new Date().toISOString() - creationTransactionDraft.linkedUser = moderator.identifier - creationTransactionDraft.user = firstUser.identifier - creationTransactionDraft.type = InputTransactionType.CREATION - creationTransactionDraft.targetDate = new Date().toISOString() - const transactionRecipeContext = new CreateTransactionRecipeContext(creationTransactionDraft) - await transactionRecipeContext.run() - const transaction = transactionRecipeContext.getTransactionRecipe() - - const context = new TransmitToIotaContext(transaction) - const debugSpy = jest.spyOn(logger, 'debug') - await context.run() - expect( - transaction.iotaMessageId?.compare( - Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'), - ), - ).toBe(0) - expect(debugSpy).toHaveBeenNthCalledWith( - 3, - expect.stringContaining('transmit LOCAL transaction to iota'), - expect.objectContaining({}), - ) - }) - - it('OUTBOUND transaction', async () => { - const crossGroupSendTransactionDraft = new TransactionDraft() - crossGroupSendTransactionDraft.amount = new Decimal('100') - crossGroupSendTransactionDraft.backendTransactionId = 4 - crossGroupSendTransactionDraft.createdAt = now.toISOString() - crossGroupSendTransactionDraft.linkedUser = foreignUser.identifier - crossGroupSendTransactionDraft.user = firstUser.identifier - crossGroupSendTransactionDraft.type = InputTransactionType.SEND - const transactionRecipeContext = new CreateTransactionRecipeContext( - crossGroupSendTransactionDraft, - ) - await transactionRecipeContext.run() - const transaction = transactionRecipeContext.getTransactionRecipe() - await transaction.save() - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body).not.toBeNull() - expect(body?.getType()).toEqual(CrossGroupType_OUTBOUND) - const context = new TransmitToIotaContext(transaction) - const debugSpy = jest.spyOn(logger, 'debug') - await context.run() - expect( - transaction.iotaMessageId?.compare( - Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'), - ), - ).toBe(0) - expect(debugSpy).toHaveBeenNthCalledWith( - 5, - expect.stringContaining('transmit OUTBOUND transaction to iota'), - expect.objectContaining({}), - ) - }) - - it('INBOUND transaction', async () => { - const crossGroupRecvTransactionDraft = new TransactionDraft() - crossGroupRecvTransactionDraft.amount = new Decimal('100') - crossGroupRecvTransactionDraft.backendTransactionId = 5 - crossGroupRecvTransactionDraft.createdAt = now.toISOString() - crossGroupRecvTransactionDraft.linkedUser = firstUser.identifier - crossGroupRecvTransactionDraft.user = foreignUser.identifier - crossGroupRecvTransactionDraft.type = InputTransactionType.RECEIVE - const transactionRecipeContext = new CreateTransactionRecipeContext( - crossGroupRecvTransactionDraft, - ) - await transactionRecipeContext.run() - const transaction = transactionRecipeContext.getTransactionRecipe() - await transaction.save() - // console.log(new TransactionLoggingView(transaction)) - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const body = deserializer.getTransactionBody() - expect(body?.getType()).toEqual(CrossGroupType_INBOUND) - - const context = new TransmitToIotaContext(transaction) - const debugSpy = jest.spyOn(logger, 'debug') - await context.run() - expect( - transaction.iotaMessageId?.compare( - Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'), - ), - ).toBe(0) - expect(debugSpy).toHaveBeenNthCalledWith( - 7, - expect.stringContaining('transmit INBOUND transaction to iota'), - expect.objectContaining({}), - ) - }) -}) diff --git a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts b/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts deleted file mode 100644 index 69c9ade3f..000000000 --- a/dlt-connector/src/interactions/transmitToIota/TransmitToIota.context.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable camelcase */ -import { Transaction } from '@entity/Transaction' -import { - CrossGroupType_INBOUND, - CrossGroupType_LOCAL, - CrossGroupType_OUTBOUND, - InteractionDeserialize, - MemoryBlock, -} from 'gradido-blockchain-js' - -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionError } from '@/graphql/model/TransactionError' -import { logger } from '@/logging/logger' -import { TransactionLoggingView } from '@/logging/TransactionLogging.view' -import { LogError } from '@/server/LogError' -import { getDataSource } from '@/typeorm/DataSource' - -import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role' -import { InboundTransactionRecipeRole } from './InboundTransactionRecipe.role' -import { LocalTransactionRecipeRole } from './LocalTransactionRecipe.role' -import { OutboundTransactionRecipeRole } from './OutboundTransactionRecipeRole' - -/** - * @DCI-Context - * Context for sending transaction recipe to iota - * send every transaction only once to iota! - */ -export class TransmitToIotaContext { - private transactionRecipeRole: AbstractTransactionRecipeRole - - public constructor(transaction: Transaction) { - const deserializer = new InteractionDeserialize(new MemoryBlock(transaction.bodyBytes)) - deserializer.run() - const transactionBody = deserializer.getTransactionBody() - if (!transactionBody) { - throw new TransactionError( - TransactionErrorType.PROTO_DECODE_ERROR, - 'error decoding body bytes', - ) - } - switch (transactionBody.getType()) { - case CrossGroupType_LOCAL: - this.transactionRecipeRole = new LocalTransactionRecipeRole(transaction) - break - case CrossGroupType_INBOUND: - this.transactionRecipeRole = new InboundTransactionRecipeRole(transaction) - break - case CrossGroupType_OUTBOUND: - this.transactionRecipeRole = new OutboundTransactionRecipeRole(transaction) - break - default: - throw new LogError('unknown cross group type', transactionBody.getType()) - } - } - - public async run(): Promise { - const transaction = await this.transactionRecipeRole.transmitToIota() - logger.debug('transaction sended via iota', new TransactionLoggingView(transaction)) - // store changes in db - // prevent endless loop - const pairingTransaction = transaction.pairingTransaction - if (pairingTransaction) { - transaction.pairingTransaction = undefined - await getDataSource().transaction(async (transactionalEntityManager) => { - await transactionalEntityManager.save(transaction) - await transactionalEntityManager.save(pairingTransaction) - }) - } else { - await transaction.save() - } - logger.info('sended transaction successfully updated in db') - } -} diff --git a/dlt-connector/src/logging/AbstractLogging.view.ts b/dlt-connector/src/logging/AbstractLogging.view.ts index e5f439b5d..ddb1cb6ed 100644 --- a/dlt-connector/src/logging/AbstractLogging.view.ts +++ b/dlt-connector/src/logging/AbstractLogging.view.ts @@ -1,6 +1,5 @@ import util from 'util' -import { Decimal } from 'decimal.js-light' import { Timestamp, TimestampSeconds } from 'gradido-blockchain-js' export abstract class AbstractLoggingView { @@ -25,13 +24,6 @@ export abstract class AbstractLoggingView { return undefined } - protected decimalToString(number: Decimal | undefined | null): string | undefined { - if (number) { - return number.toString() - } - return undefined - } - protected timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { if (timestamp && timestamp.getSeconds()) { return timestamp.getDate().toISOString() diff --git a/dlt-connector/src/logging/AccountLogging.view.ts b/dlt-connector/src/logging/AccountLogging.view.ts deleted file mode 100644 index f1a7abe20..000000000 --- a/dlt-connector/src/logging/AccountLogging.view.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Account } from '@entity/Account' -import { addressTypeToString } from 'gradido-blockchain-js' - -import { AccountType } from '@/graphql/enum/AccountType' -import { accountTypeToAddressType } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { UserLoggingView } from './UserLogging.view' - -export class AccountLoggingView extends AbstractLoggingView { - public constructor(private account: Account) { - super() - } - - public toJSON() { - return { - id: this.account.id, - user: this.account.user ? new UserLoggingView(this.account.user).toJSON() : null, - derivationIndex: this.account.derivationIndex, - derive2Pubkey: this.account.derive2Pubkey.toString(this.bufferStringFormat), - type: addressTypeToString( - accountTypeToAddressType(this.account.type as unknown as AccountType), - ), - createdAt: this.dateToString(this.account.createdAt), - confirmedAt: this.dateToString(this.account.confirmedAt), - balanceOnConfirmation: this.decimalToString(this.account.balanceOnConfirmation), - balanceConfirmedAt: this.dateToString(this.account.balanceConfirmedAt), - balanceOnCreation: this.decimalToString(this.account.balanceOnCreation), - balanceCreatedAt: this.dateToString(this.account.balanceCreatedAt), - } - } -} diff --git a/dlt-connector/src/logging/BackendTransactionLogging.view.ts b/dlt-connector/src/logging/BackendTransactionLogging.view.ts deleted file mode 100644 index d21c765aa..000000000 --- a/dlt-connector/src/logging/BackendTransactionLogging.view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { BackendTransaction } from '@entity/BackendTransaction' - -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { getEnumValue } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { TransactionLoggingView } from './TransactionLogging.view' - -export class BackendTransactionLoggingView extends AbstractLoggingView { - public constructor(private self: BackendTransaction) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(showTransaction = true): any { - return { - id: this.self.id, - backendTransactionId: this.self.backendTransactionId, - transaction: - showTransaction && this.self.transaction - ? new TransactionLoggingView(this.self.transaction).toJSON(false) - : undefined, - type: getEnumValue(InputTransactionType, this.self.typeId), - balance: this.decimalToString(this.self.balance), - createdAt: this.dateToString(this.self.createdAt), - confirmedAt: this.dateToString(this.self.confirmedAt), - verifiedOnBackend: this.self.verifiedOnBackend, - } - } -} diff --git a/dlt-connector/src/logging/CommunityLogging.view.ts b/dlt-connector/src/logging/CommunityLogging.view.ts deleted file mode 100644 index 22f0a4597..000000000 --- a/dlt-connector/src/logging/CommunityLogging.view.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Community } from '@entity/Community' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { AccountLoggingView } from './AccountLogging.view' - -export class CommunityLoggingView extends AbstractLoggingView { - public constructor(private self: Community) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - id: this.self.id, - iotaTopic: this.self.iotaTopic, - foreign: this.self.foreign, - publicKey: this.self.rootPubkey?.toString(this.bufferStringFormat), - createdAt: this.dateToString(this.self.createdAt), - confirmedAt: this.dateToString(this.self.confirmedAt), - aufAccount: this.self.aufAccount ? new AccountLoggingView(this.self.aufAccount) : undefined, - gmwAccount: this.self.gmwAccount ? new AccountLoggingView(this.self.gmwAccount) : undefined, - } - } -} diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index 5e86822ec..655a9ab9e 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -16,7 +16,7 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { user: new UserIdentifierLoggingView(this.self.user).toJSON(), linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), backendTransactionId: this.self.backendTransactionId, - amount: this.decimalToString(this.self.amount), + amount: Number(this.self.amount), type: getEnumValue(InputTransactionType, this.self.type), createdAt: this.self.createdAt, targetDate: this.self.targetDate, diff --git a/dlt-connector/src/logging/TransactionLogging.view.ts b/dlt-connector/src/logging/TransactionLogging.view.ts deleted file mode 100644 index 1bb59cc55..000000000 --- a/dlt-connector/src/logging/TransactionLogging.view.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Transaction } from '@entity/Transaction' - -import { TransactionType } from '@/data/proto/3_3/enum/TransactionType' -import { LogError } from '@/server/LogError' -import { getEnumValue } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { AccountLoggingView } from './AccountLogging.view' -import { BackendTransactionLoggingView } from './BackendTransactionLogging.view' -import { CommunityLoggingView } from './CommunityLogging.view' - -export class TransactionLoggingView extends AbstractLoggingView { - public constructor(private self: Transaction) { - super() - if (this.self.community === undefined) { - throw new LogError('sender community is zero') - } - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(showBackendTransactions = true, deep = 1): any { - return { - id: this.self.id, - nr: this.self.nr, - bodyBytesLength: this.self.bodyBytes.length, - createdAt: this.dateToString(this.self.createdAt), - confirmedAt: this.dateToString(this.self.confirmedAt), - protocolVersion: this.self.protocolVersion, - type: getEnumValue(TransactionType, this.self.type), - signature: this.self.signature.subarray(0, 31).toString(this.bufferStringFormat) + '..', - community: new CommunityLoggingView(this.self.community).toJSON(), - otherCommunity: this.self.otherCommunity - ? new CommunityLoggingView(this.self.otherCommunity) - : { id: this.self.otherCommunityId }, - iotaMessageId: this.self.iotaMessageId - ? this.self.iotaMessageId.toString(this.bufferStringFormat) - : undefined, - signingAccount: this.self.signingAccount - ? new AccountLoggingView(this.self.signingAccount) - : { id: this.self.signingAccountId }, - recipientAccount: this.self.recipientAccount - ? new AccountLoggingView(this.self.recipientAccount) - : { id: this.self.recipientAccountId }, - pairingTransaction: - this.self.pairingTransaction && deep === 1 - ? new TransactionLoggingView(this.self.pairingTransaction).toJSON( - showBackendTransactions, - deep + 1, - ) - : { id: this.self.pairingTransaction }, - amount: this.decimalToString(this.self.amount), - accountBalanceOnCreation: this.decimalToString(this.self.accountBalanceOnCreation), - accountBalanceOnConfirmation: this.decimalToString(this.self.accountBalanceOnConfirmation), - runningHash: this.self.runningHash - ? this.self.runningHash.toString(this.bufferStringFormat) - : undefined, - iotaMilestone: this.self.iotaMilestone, - backendTransactions: - showBackendTransactions && this.self.backendTransactions - ? this.self.backendTransactions.map((backendTransaction) => - new BackendTransactionLoggingView(backendTransaction).toJSON(false), - ) - : undefined, - } - } -} diff --git a/dlt-connector/src/logging/UserLogging.view.ts b/dlt-connector/src/logging/UserLogging.view.ts deleted file mode 100644 index a3cbd66bc..000000000 --- a/dlt-connector/src/logging/UserLogging.view.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { User } from '@entity/User' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class UserLoggingView extends AbstractLoggingView { - public constructor(private user: User) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - id: this.user.id, - gradidoId: this.user.gradidoID, - derive1Pubkey: this.user.derive1Pubkey.toString(this.bufferStringFormat), - createdAt: this.dateToString(this.user.createdAt), - confirmedAt: this.dateToString(this.user.confirmedAt), - } - } -} diff --git a/dlt-connector/src/manager/InterruptiveSleepManager.ts b/dlt-connector/src/manager/InterruptiveSleepManager.ts deleted file mode 100644 index 7827c8fe9..000000000 --- a/dlt-connector/src/manager/InterruptiveSleepManager.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { LogError } from '@/server/LogError' - -import { InterruptiveSleep } from '../utils/InterruptiveSleep' - -// Source: https://refactoring.guru/design-patterns/singleton/typescript/example -// and ../federation/client/FederationClientFactory.ts -/** - * A Singleton class defines the `getInstance` method that lets clients access - * the unique singleton instance. - */ -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class InterruptiveSleepManager { - // eslint-disable-next-line no-use-before-define - private static instance: InterruptiveSleepManager - private interruptiveSleep: Map = new Map() - private stepSizeMilliseconds = 10 - - /** - * The Singleton's constructor should always be private to prevent direct - * construction calls with the `new` operator. - */ - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor() {} - - /** - * The static method that controls the access to the singleton instance. - * - * This implementation let you subclass the Singleton class while keeping - * just one instance of each subclass around. - */ - public static getInstance(): InterruptiveSleepManager { - if (!InterruptiveSleepManager.instance) { - InterruptiveSleepManager.instance = new InterruptiveSleepManager() - } - return InterruptiveSleepManager.instance - } - - /** - * only for new created InterruptiveSleepManager Entries! - * @param step size in ms in which new! InterruptiveSleepManager check if they where triggered - */ - public setStepSize(ms: number) { - this.stepSizeMilliseconds = ms - } - - public interrupt(key: string): void { - const interruptiveSleep = this.interruptiveSleep.get(key) - if (interruptiveSleep) { - interruptiveSleep.interrupt() - } - } - - public sleep(key: string, ms: number): Promise { - if (!this.interruptiveSleep.has(key)) { - this.interruptiveSleep.set(key, new InterruptiveSleep(this.stepSizeMilliseconds)) - } - const interruptiveSleep = this.interruptiveSleep.get(key) - if (!interruptiveSleep) { - throw new LogError('map entry not exist after setting it') - } - return interruptiveSleep.sleep(ms) - } -} diff --git a/dlt-connector/src/tasks/transmitToIota.ts b/dlt-connector/src/tasks/transmitToIota.ts deleted file mode 100644 index 89236586e..000000000 --- a/dlt-connector/src/tasks/transmitToIota.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const' -import { TransactionRepository } from '@/data/Transaction.repository' -import { TransmitToIotaContext } from '@/interactions/transmitToIota/TransmitToIota.context' -import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager' - -import { logger } from '../logging/logger' - -function sleep(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms) - }) -} - -let running = true - -export const stopTransmitToIota = (): void => { - running = false -} -/** - * check for pending transactions: - * - if one found call TransmitToIotaContext - * - if not, wait 1000 ms and try again - * if a new transaction was added, the sleep will be interrupted - */ -export const transmitToIota = async (): Promise => { - logger.info('start iota message transmitter') - // eslint-disable-next-line no-unmodified-loop-condition - while (running) { - try { - while (true) { - const recipe = await TransactionRepository.getNextPendingTransaction() - if (!recipe) break - const transmitToIotaContext = new TransmitToIotaContext(recipe) - await transmitToIotaContext.run() - } - - await InterruptiveSleepManager.getInstance().sleep( - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, - 1000, - ) - } catch (error) { - logger.error('error while transmitting to iota, retry in 10 seconds ', error) - await sleep(10000) - } - } - logger.error( - 'end iota message transmitter, no further transaction will be transmitted. !!! Please restart Server !!!', - ) -} diff --git a/dlt-connector/src/utils/InterruptiveSleep.ts b/dlt-connector/src/utils/InterruptiveSleep.ts deleted file mode 100644 index c21e57db9..000000000 --- a/dlt-connector/src/utils/InterruptiveSleep.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Sleep, that can be interrupted - * call sleep only for msSteps and than check if interrupt was called - */ -export class InterruptiveSleep { - private interruptSleep = false - private msSteps = 10 - - constructor(msSteps: number) { - this.msSteps = msSteps - } - - public interrupt(): void { - this.interruptSleep = true - } - - private static _sleep(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms) - }) - } - - public async sleep(ms: number): Promise { - let waited = 0 - this.interruptSleep = false - while (waited < ms && !this.interruptSleep) { - await InterruptiveSleep._sleep(this.msSteps) - waited += this.msSteps - } - } -} From c4697a010a7839e4d0e8170ff4e4c6e999e98bf6 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sun, 22 Sep 2024 17:06:17 +0200 Subject: [PATCH 010/226] remove dlt-database --- .github/workflows/test_dlt_connector.yml | 9 +- dlt-connector/package.json | 5 +- dlt-database/.env.dist | 6 - dlt-database/.env.template | 8 - dlt-database/.eslintignore | 3 - dlt-database/.eslintrc.js | 206 -- dlt-database/.gitignore | 27 - dlt-database/.nvmrc | 1 - dlt-database/.prettierrc.js | 9 - dlt-database/Dockerfile | 130 - dlt-database/README.md | 39 - dlt-database/entity/0001-init_db/Account.ts | 81 - .../entity/0001-init_db/AccountCommunity.ts | 30 - dlt-database/entity/0001-init_db/Community.ts | 69 - .../0001-init_db/ConfirmedTransaction.ts | 59 - .../entity/0001-init_db/InvalidTransaction.ts | 10 - dlt-database/entity/0001-init_db/Migration.ts | 13 - .../entity/0001-init_db/TransactionRecipe.ts | 83 - dlt-database/entity/0001-init_db/User.ts | 40 - .../0002-refactor_add_community/Account.ts | 80 - .../AccountCommunity.ts | 30 - .../0002-refactor_add_community/Community.ts | 69 - .../ConfirmedTransaction.ts | 59 - .../0002-refactor_add_community/User.ts | 39 - .../Account.ts | 89 - .../BackendTransaction.ts | 46 - .../Community.ts | 64 - .../InvalidTransaction.ts | 13 - .../Transaction.ts | 129 - .../0003-refactor_transaction_recipe/User.ts | 35 - .../entity/0004-fix_spelling/Transaction.ts | 129 - .../Community.ts | 64 - .../Transaction.ts | 109 - dlt-database/entity/Account.ts | 1 - dlt-database/entity/AccountCommunity.ts | 1 - dlt-database/entity/Community.ts | 1 - dlt-database/entity/InvalidTransaction.ts | 1 - dlt-database/entity/Migration.ts | 1 - dlt-database/entity/Transaction.ts | 1 - dlt-database/entity/User.ts | 1 - dlt-database/entity/index.ts | 17 - dlt-database/log/.gitignore | 2 - dlt-database/migrations/0001-init_db.ts | 130 - .../migrations/0002-refactor_add_community.ts | 61 - .../0003-refactor_transaction_recipe.ts | 156 - dlt-database/migrations/0004-fix_spelling.ts | 15 - ...05-refactor_with_gradido_blockchain_lib.ts | 28 - dlt-database/package.json | 55 - dlt-database/src/config/index.ts | 39 - dlt-database/src/index.ts | 56 - dlt-database/src/prepare.ts | 22 - dlt-database/src/typeorm.ts | 1 - .../src/typeorm/DecimalTransformer.ts | 19 - dlt-database/tsconfig.json | 73 - dlt-database/yarn.lock | 2594 ----------------- docker-compose.apple-m1.override.yml | 6 - docker-compose.override.yml | 22 - docker-compose.reset.yml | 27 - docker-compose.test.yml | 12 - docker-compose.yml | 26 - 60 files changed, 2 insertions(+), 5149 deletions(-) delete mode 100644 dlt-database/.env.dist delete mode 100644 dlt-database/.env.template delete mode 100644 dlt-database/.eslintignore delete mode 100644 dlt-database/.eslintrc.js delete mode 100644 dlt-database/.gitignore delete mode 100644 dlt-database/.nvmrc delete mode 100644 dlt-database/.prettierrc.js delete mode 100644 dlt-database/Dockerfile delete mode 100644 dlt-database/README.md delete mode 100644 dlt-database/entity/0001-init_db/Account.ts delete mode 100644 dlt-database/entity/0001-init_db/AccountCommunity.ts delete mode 100644 dlt-database/entity/0001-init_db/Community.ts delete mode 100644 dlt-database/entity/0001-init_db/ConfirmedTransaction.ts delete mode 100644 dlt-database/entity/0001-init_db/InvalidTransaction.ts delete mode 100644 dlt-database/entity/0001-init_db/Migration.ts delete mode 100644 dlt-database/entity/0001-init_db/TransactionRecipe.ts delete mode 100644 dlt-database/entity/0001-init_db/User.ts delete mode 100644 dlt-database/entity/0002-refactor_add_community/Account.ts delete mode 100644 dlt-database/entity/0002-refactor_add_community/AccountCommunity.ts delete mode 100644 dlt-database/entity/0002-refactor_add_community/Community.ts delete mode 100644 dlt-database/entity/0002-refactor_add_community/ConfirmedTransaction.ts delete mode 100644 dlt-database/entity/0002-refactor_add_community/User.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/Account.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/Community.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/InvalidTransaction.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts delete mode 100644 dlt-database/entity/0003-refactor_transaction_recipe/User.ts delete mode 100644 dlt-database/entity/0004-fix_spelling/Transaction.ts delete mode 100644 dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts delete mode 100644 dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts delete mode 100644 dlt-database/entity/Account.ts delete mode 100644 dlt-database/entity/AccountCommunity.ts delete mode 100644 dlt-database/entity/Community.ts delete mode 100644 dlt-database/entity/InvalidTransaction.ts delete mode 100644 dlt-database/entity/Migration.ts delete mode 100644 dlt-database/entity/Transaction.ts delete mode 100644 dlt-database/entity/User.ts delete mode 100644 dlt-database/entity/index.ts delete mode 100644 dlt-database/log/.gitignore delete mode 100644 dlt-database/migrations/0001-init_db.ts delete mode 100644 dlt-database/migrations/0002-refactor_add_community.ts delete mode 100644 dlt-database/migrations/0003-refactor_transaction_recipe.ts delete mode 100644 dlt-database/migrations/0004-fix_spelling.ts delete mode 100644 dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts delete mode 100644 dlt-database/package.json delete mode 100644 dlt-database/src/config/index.ts delete mode 100644 dlt-database/src/index.ts delete mode 100644 dlt-database/src/prepare.ts delete mode 100644 dlt-database/src/typeorm.ts delete mode 100644 dlt-database/src/typeorm/DecimalTransformer.ts delete mode 100644 dlt-database/tsconfig.json delete mode 100644 dlt-database/yarn.lock diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index 099f0dd1a..8716b0c5e 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -60,13 +60,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 - - - name: DLT-Connector | docker-compose mariadb - run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb - - - name: Sleep for 30 seconds - run: sleep 30s - shell: bash - name: DLT-Connector | Unit tests - run: cd dlt-database && yarn && yarn build && cd ../dlt-connector && yarn && yarn test + run: cd dlt-connector && yarn && yarn test diff --git a/dlt-connector/package.json b/dlt-connector/package.json index ca889b833..6031dd3b0 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -1,6 +1,6 @@ { "name": "gradido-dlt-connector", - "version": "2.3.1", + "version": "3.0.0", "description": "Gradido DLT-Connector", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/", @@ -23,7 +23,6 @@ "class-validator": "^0.14.0", "cors": "^2.8.5", "cross-env": "^7.0.3", - "dlt-database": "file:../dlt-database", "dotenv": "10.0.0", "express": "4.17.1", "express-slow-down": "^2.0.1", @@ -66,8 +65,6 @@ "prettier": "^2.8.7", "ts-jest": "^27.0.5", "ts-node": "^10.9.1", - "typeorm": "^0.3.17", - "typeorm-extension": "^3.0.1", "typescript": "^4.9.4" }, "engines": { diff --git a/dlt-database/.env.dist b/dlt-database/.env.dist deleted file mode 100644 index ecee20a06..000000000 --- a/dlt-database/.env.dist +++ /dev/null @@ -1,6 +0,0 @@ -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_dlt -MIGRATIONS_TABLE=migrations diff --git a/dlt-database/.env.template b/dlt-database/.env.template deleted file mode 100644 index 5b875bb6e..000000000 --- a/dlt-database/.env.template +++ /dev/null @@ -1,8 +0,0 @@ -CONFIG_VERSION=$DATABASE_CONFIG_VERSION - -DB_HOST=localhost -DB_PORT=3306 -DB_USER=$DB_USER -DB_PASSWORD=$DB_PASSWORD -DB_DATABASE=gradido_dlt -MIGRATIONS_TABLE=migrations diff --git a/dlt-database/.eslintignore b/dlt-database/.eslintignore deleted file mode 100644 index f6b255e92..000000000 --- a/dlt-database/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -**/*.min.js -build \ No newline at end of file diff --git a/dlt-database/.eslintrc.js b/dlt-database/.eslintrc.js deleted file mode 100644 index 6f1db58ff..000000000 --- a/dlt-database/.eslintrc.js +++ /dev/null @@ -1,206 +0,0 @@ -// eslint-disable-next-line import/no-commonjs, import/unambiguous -module.exports = { - root: true, - env: { - node: true, - }, - parser: '@typescript-eslint/parser', - plugins: ['prettier', '@typescript-eslint', 'import', 'n', 'promise'], - extends: [ - 'standard', - 'eslint:recommended', - 'plugin:prettier/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript', - // 'plugin:security/recommended', - 'plugin:@eslint-community/eslint-comments/recommended', - ], - settings: { - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - project: ['./tsconfig.json'], - }, - node: true, - }, - }, - rules: { - 'no-console': 'error', - camelcase: 'error', - 'no-debugger': 'error', - 'prettier/prettier': [ - 'error', - { - htmlWhitespaceSensitivity: 'ignore', - }, - ], - // import - 'import/export': 'error', - 'import/no-deprecated': 'error', - 'import/no-empty-named-blocks': 'error', - // 'import/no-extraneous-dependencies': 'error', - 'import/no-mutable-exports': 'error', - 'import/no-unused-modules': 'error', - 'import/no-named-as-default': 'error', - 'import/no-named-as-default-member': 'error', - 'import/no-amd': 'error', - 'import/no-commonjs': 'error', - 'import/no-import-module-exports': 'error', - 'import/no-nodejs-modules': 'off', - 'import/unambiguous': 'error', - 'import/default': 'error', - 'import/named': 'error', - 'import/namespace': 'error', - 'import/no-absolute-path': 'error', - // 'import/no-cycle': 'error', - 'import/no-dynamic-require': 'error', - 'import/no-internal-modules': 'off', - 'import/no-relative-packages': 'error', - // 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }], - 'import/no-self-import': 'error', - 'import/no-unresolved': 'error', - 'import/no-useless-path-segments': 'error', - 'import/no-webpack-loader-syntax': 'error', - 'import/consistent-type-specifier-style': 'error', - 'import/exports-last': 'off', - 'import/extensions': 'error', - 'import/first': 'error', - 'import/group-exports': 'off', - 'import/newline-after-import': 'error', - 'import/no-anonymous-default-export': 'error', - 'import/no-default-export': 'error', - 'import/no-duplicates': 'error', - 'import/no-named-default': 'error', - 'import/no-namespace': 'error', - 'import/no-unassigned-import': 'error', - // 'import/order': [ - // 'error', - // { - // groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - // 'newlines-between': 'always', - // pathGroups: [ - // { - // pattern: '@?*/**', - // group: 'external', - // position: 'after', - // }, - // { - // pattern: '@/**', - // group: 'external', - // position: 'after', - // }, - // ], - // alphabetize: { - // order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */, - // caseInsensitive: true /* ignore case. Options: [true, false] */, - // }, - // distinctGroup: true, - // }, - // ], - 'import/prefer-default-export': 'off', - // n - 'n/handle-callback-err': 'error', - 'n/no-callback-literal': 'error', - 'n/no-exports-assign': 'error', - // 'n/no-extraneous-import': 'error', - 'n/no-extraneous-require': 'error', - 'n/no-hide-core-modules': 'error', - 'n/no-missing-import': 'off', // not compatible with typescript - 'n/no-missing-require': 'error', - 'n/no-new-require': 'error', - 'n/no-path-concat': 'error', - // 'n/no-process-exit': 'error', - 'n/no-unpublished-bin': 'error', - 'n/no-unpublished-import': 'off', // TODO need to exclude seeds - 'n/no-unpublished-require': 'error', - 'n/no-unsupported-features': ['error', { ignores: ['modules'] }], - 'n/no-unsupported-features/es-builtins': 'error', - 'n/no-unsupported-features/es-syntax': 'error', - 'n/no-unsupported-features/node-builtins': 'error', - 'n/process-exit-as-throw': 'error', - 'n/shebang': 'error', - 'n/callback-return': 'error', - 'n/exports-style': 'error', - 'n/file-extension-in-import': 'off', - 'n/global-require': 'error', - 'n/no-mixed-requires': 'error', - 'n/no-process-env': 'error', - 'n/no-restricted-import': 'error', - 'n/no-restricted-require': 'error', - // 'n/no-sync': 'error', - 'n/prefer-global/buffer': 'error', - 'n/prefer-global/console': 'error', - 'n/prefer-global/process': 'error', - 'n/prefer-global/text-decoder': 'error', - 'n/prefer-global/text-encoder': 'error', - 'n/prefer-global/url': 'error', - 'n/prefer-global/url-search-params': 'error', - 'n/prefer-promises/dns': 'error', - // 'n/prefer-promises/fs': 'error', - // promise - // 'promise/catch-or-return': 'error', - // 'promise/no-return-wrap': 'error', - // 'promise/param-names': 'error', - // 'promise/always-return': 'error', - // 'promise/no-native': 'off', - // 'promise/no-nesting': 'warn', - // 'promise/no-promise-in-callback': 'warn', - // 'promise/no-callback-in-promise': 'warn', - // 'promise/avoid-new': 'warn', - // 'promise/no-new-statics': 'error', - // 'promise/no-return-in-finally': 'warn', - // 'promise/valid-params': 'warn', - // 'promise/prefer-await-to-callbacks': 'error', - // 'promise/no-multiple-resolved': 'error', - // eslint comments - '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], - '@eslint-community/eslint-comments/no-restricted-disable': 'error', - '@eslint-community/eslint-comments/no-use': 'off', - '@eslint-community/eslint-comments/require-description': 'off', - }, - overrides: [ - // only for ts files - { - files: ['*.ts', '*.tsx'], - extends: [ - // 'plugin:@typescript-eslint/recommended', - // 'plugin:@typescript-eslint/recommended-requiring-type-checking', - // 'plugin:@typescript-eslint/strict', - ], - rules: { - // allow explicitly defined dangling promises - // '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], - 'no-void': ['error', { allowAsStatement: true }], - // ignore prefer-regexp-exec rule to allow string.match(regex) - '@typescript-eslint/prefer-regexp-exec': 'off', - // this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486 - 'import/unambiguous': 'off', - // this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - // this is to properly reference the referenced project database without requirement of compiling it - // eslint-disable-next-line camelcase - EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, - }, - }, - // we do not have testing on the database - // { - // files: ['*.test.ts'], - // plugins: ['jest'], - // rules: { - // 'jest/no-disabled-tests': 'error', - // 'jest/no-focused-tests': 'error', - // 'jest/no-identical-title': 'error', - // 'jest/prefer-to-have-length': 'error', - // 'jest/valid-expect': 'error', - // '@typescript-eslint/unbound-method': 'off', - // 'jest/unbound-method': 'error', - // }, - // }, - ], -} diff --git a/dlt-database/.gitignore b/dlt-database/.gitignore deleted file mode 100644 index 9e9e01ced..000000000 --- a/dlt-database/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -.DS_Store -node_modules/ -build/ -.cache/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* -test/unit/coverage - -package-lock.json -/.env -/.env.bak -.env.development.local -.env.production.local - -# Editor directories and files -.idea -*.suo -*.ntvs* -*.njsproj -*.sln - -# coverage folder - -coverage/ - -*~ diff --git a/dlt-database/.nvmrc b/dlt-database/.nvmrc deleted file mode 100644 index 02c4afe7d..000000000 --- a/dlt-database/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v18.7.0 \ No newline at end of file diff --git a/dlt-database/.prettierrc.js b/dlt-database/.prettierrc.js deleted file mode 100644 index bc1d767d7..000000000 --- a/dlt-database/.prettierrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - semi: false, - printWidth: 100, - singleQuote: true, - trailingComma: "all", - tabWidth: 2, - bracketSpacing: true, - endOfLine: "auto", -}; diff --git a/dlt-database/Dockerfile b/dlt-database/Dockerfile deleted file mode 100644 index e34a4dbb6..000000000 --- a/dlt-database/Dockerfile +++ /dev/null @@ -1,130 +0,0 @@ -################################################################################## -# BASE ########################################################################### -################################################################################## -FROM node:18.7.0-alpine3.16 as base - -# ENVs (available in production aswell, can be overwritten by commandline or env file) -## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame -ENV DOCKER_WORKDIR="/app" -## We Cannot do `$(date -u +'%Y-%m-%dT%H:%M:%SZ')` here so we use unix timestamp=0 -ENV BUILD_DATE="1970-01-01T00:00:00.00Z" -## We cannot do $(npm run version).${BUILD_NUMBER} here so we default to 0.0.0.0 -ENV BUILD_VERSION="0.0.0.0" -## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000 -ENV BUILD_COMMIT="0000000" -## SET NODE_ENV -ENV NODE_ENV="production" - -# Labels -LABEL org.label-schema.build-date="${BUILD_DATE}" -LABEL org.label-schema.name="gradido:database" -LABEL org.label-schema.description="Gradido Database Migration Service" -LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md" -LABEL org.label-schema.url="https://gradido.net" -LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/database" -LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}" -LABEL org.label-schema.vendor="Gradido Community" -LABEL org.label-schema.version="${BUILD_VERSION}" -LABEL org.label-schema.schema-version="1.0" -LABEL maintainer="support@gradido.net" - -# Install Additional Software -## install: git -#RUN apk --no-cache add git - -## Workdir -RUN mkdir -p ${DOCKER_WORKDIR} -WORKDIR ${DOCKER_WORKDIR} - -################################################################################## -# DEVELOPMENT (Connected to the local environment, to reload on demand) ########## -################################################################################## -FROM base as development - -# We don't need to copy or build anything since we gonna bind to the -# local filesystem which will need a rebuild anyway - -# Run command -# (for development we need to execute npm install since the -# node_modules are on another volume and need updating) -CMD /bin/sh -c "yarn install" - -################################################################################## -# BUILD (Does contain all files and is therefore bloated) ######################## -################################################################################## -FROM base as build - -# Copy everything -COPY . . -# npm install -RUN yarn install --production=false --frozen-lockfile --non-interactive -# npm build -RUN yarn run build - -################################################################################## -# TEST UP ######################################################################## -################################################################################## -FROM build as test_up - -# Run command -CMD /bin/sh -c "yarn install && yarn run dev_up" - -################################################################################## -# TEST RESET ##################################################################### -################################################################################## -FROM build as test_reset - -# Run command -CMD /bin/sh -c "yarn install && yarn run dev_reset" - -################################################################################## -# TEST DOWN ###################################################################### -################################################################################## -FROM build as test_down - -# Run command -CMD /bin/sh -c "yarn install && yarn run dev_down" - -################################################################################## -# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) # -################################################################################## -FROM base as production - -# Copy "binary"-files from build image -COPY --from=build ${DOCKER_WORKDIR}/build ./build -# We also copy the node_modules express and serve-static for the run script -COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules -# Copy static files -# COPY --from=build ${DOCKER_WORKDIR}/public ./public -# Copy package.json for script definitions (lock file should not be needed) -COPY --from=build ${DOCKER_WORKDIR}/package.json ./package.json -# Copy Mnemonic files -COPY --from=build ${DOCKER_WORKDIR}/src/config/*.txt ./src/config/ -# Copy log folder -COPY --from=build ${DOCKER_WORKDIR}/log ./log -# Copy run scripts run/ -# COPY --from=build ${DOCKER_WORKDIR}/run ./run - -################################################################################## -# PRODUCTION UP ################################################################## -################################################################################## -FROM production as production_up - -# Run command -CMD /bin/sh -c "yarn run up" - -################################################################################## -# PRODUCTION RESET ############################################################### -################################################################################## -FROM production as production_reset - -# Run command -CMD /bin/sh -c "yarn run reset" - -################################################################################## -# PRODUCTION DOWN ################################################################ -################################################################################## -FROM production as production_down - -# Run command -CMD /bin/sh -c "yarn run down" \ No newline at end of file diff --git a/dlt-database/README.md b/dlt-database/README.md deleted file mode 100644 index e951f4530..000000000 --- a/dlt-database/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# database - -## Project setup - -```bash -yarn install -``` - -## Upgrade migrations production - -```bash -yarn up -``` - -## Upgrade migrations development - -```bash -yarn dev_up -``` - -## Downgrade migrations production - -```bash -yarn down -``` - -## Downgrade migrations development - -```bash -yarn dev_down -``` - -## Reset database - -```bash -yarn dev_reset -``` - -Runs all down migrations and after this all up migrations. diff --git a/dlt-database/entity/0001-init_db/Account.ts b/dlt-database/entity/0001-init_db/Account.ts deleted file mode 100644 index 7ceaf09cc..000000000 --- a/dlt-database/entity/0001-init_db/Account.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - JoinColumn, - OneToMany, - BaseEntity, -} from 'typeorm' -import { User } from '../User' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from './TransactionRecipe' -// ConfirmedTransaction was removed in newer migrations, so only the version from this folder can be linked -import { ConfirmedTransaction } from './ConfirmedTransaction' -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Decimal } from 'decimal.js-light' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('accounts') -export class Account extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @ManyToOne(() => User, (user) => user.accounts) // Assuming you have a User entity with 'accounts' relation - @JoinColumn({ name: 'user_id' }) - user?: User - - // if user id is null, account belongs to community gmw or auf - @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true }) - userId?: number - - @Column({ name: 'derivation_index', type: 'int', unsigned: true }) - derivationIndex: number - - @Column({ name: 'derive2_pubkey', type: 'binary', length: 32, unique: true }) - derive2Pubkey: Buffer - - @Column({ type: 'tinyint', unsigned: true }) - type: number - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ name: 'confirmed_at', type: 'datetime', precision: 3, nullable: true }) - confirmedAt?: Date - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - default: 0, - transformer: DecimalTransformer, - }) - balance: Decimal - - @Column({ - name: 'balance_date', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - balanceDate: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.account) - @JoinColumn({ name: 'account_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.signingAccount) - transactionRecipesSigning?: TransactionRecipe[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.recipientAccount) - transactionRecipesRecipient?: TransactionRecipe[] - - @OneToMany(() => ConfirmedTransaction, (transaction) => transaction.account) - confirmedTransactions?: ConfirmedTransaction[] -} diff --git a/dlt-database/entity/0001-init_db/AccountCommunity.ts b/dlt-database/entity/0001-init_db/AccountCommunity.ts deleted file mode 100644 index 4c56b7954..000000000 --- a/dlt-database/entity/0001-init_db/AccountCommunity.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, BaseEntity } from 'typeorm' - -import { Account } from '../Account' -import { Community } from '../Community' - -@Entity('accounts_communities') -export class AccountCommunity extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @ManyToOne(() => Account, (account) => account.accountCommunities) - @JoinColumn({ name: 'account_id' }) - account: Account - - @Column({ name: 'account_id', type: 'int', unsigned: true }) - accountId: number - - @ManyToOne(() => Community, (community) => community.accountCommunities) - @JoinColumn({ name: 'community_id' }) - community: Community - - @Column({ name: 'community_id', type: 'int', unsigned: true }) - communityId: number - - @Column({ name: 'valid_from', type: 'datetime', precision: 3 }) - validFrom: Date - - @Column({ name: 'valid_to', type: 'datetime', precision: 3, nullable: true }) - validTo?: Date -} diff --git a/dlt-database/entity/0001-init_db/Community.ts b/dlt-database/entity/0001-init_db/Community.ts deleted file mode 100644 index 943914878..000000000 --- a/dlt-database/entity/0001-init_db/Community.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - JoinColumn, - OneToOne, - OneToMany, - BaseEntity, -} from 'typeorm' -import { Account } from '../Account' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from './TransactionRecipe' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('communities') -export class Community extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'iota_topic', collation: 'utf8mb4_unicode_ci' }) - iotaTopic: string - - @Column({ name: 'root_pubkey', type: 'binary', length: 32, unique: true }) - rootPubkey: Buffer - - @Column({ name: 'root_privkey', type: 'binary', length: 32, nullable: true }) - rootPrivkey?: Buffer - - @Column({ name: 'root_chaincode', type: 'binary', length: 32, nullable: true }) - rootChaincode?: Buffer - - @Column({ type: 'tinyint', default: true }) - foreign: boolean - - @Column({ name: 'gmw_account_id', type: 'int', unsigned: true, nullable: true }) - gmwAccountId?: number - - @OneToOne(() => Account) - @JoinColumn({ name: 'gmw_account_id' }) - gmwAccount?: Account - - @Column({ name: 'auf_account_id', type: 'int', unsigned: true, nullable: true }) - aufAccountId?: number - - @OneToOne(() => Account) - @JoinColumn({ name: 'auf_account_id' }) - aufAccount?: Account - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ name: 'confirmed_at', type: 'datetime', precision: 3, nullable: true }) - confirmedAt?: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.community) - @JoinColumn({ name: 'community_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.senderCommunity) - transactionRecipesSender?: TransactionRecipe[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.recipientCommunity) - transactionRecipesRecipient?: TransactionRecipe[] -} diff --git a/dlt-database/entity/0001-init_db/ConfirmedTransaction.ts b/dlt-database/entity/0001-init_db/ConfirmedTransaction.ts deleted file mode 100644 index 408a58a69..000000000 --- a/dlt-database/entity/0001-init_db/ConfirmedTransaction.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - JoinColumn, - OneToOne, - BaseEntity, -} from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -// the relation in future account don't match which this any longer, so we can only link with the local account here -import { Account } from './Account' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from './TransactionRecipe' - -@Entity('confirmed_transactions') -export class ConfirmedTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @OneToOne(() => TransactionRecipe, (recipe) => recipe.confirmedTransaction) - @JoinColumn({ name: 'transaction_recipe_id' }) - transactionRecipe: TransactionRecipe - - @Column({ name: 'transaction_recipe_id', type: 'int', unsigned: true }) - transactionRecipeId: number - - @Column({ type: 'bigint' }) - nr: number - - @Column({ type: 'binary', length: 48 }) - runningHash: Buffer - - @ManyToOne(() => Account, (account) => account.confirmedTransactions) - @JoinColumn({ name: 'account_id' }) - account: Account - - @Column({ name: 'account_id', type: 'int', unsigned: true }) - accountId: number - - @Column({ - name: 'account_balance', - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - default: 0, - transformer: DecimalTransformer, - }) - accountBalance: Decimal - - @Column({ name: 'iota_milestone', type: 'bigint' }) - iotaMilestone: number - - @Column({ name: 'confirmed_at', type: 'datetime', precision: 3 }) - confirmedAt: Date -} diff --git a/dlt-database/entity/0001-init_db/InvalidTransaction.ts b/dlt-database/entity/0001-init_db/InvalidTransaction.ts deleted file mode 100644 index 1e9be4ff4..000000000 --- a/dlt-database/entity/0001-init_db/InvalidTransaction.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm' - -@Entity('invalid_transactions') -export class InvalidTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32 }) - iotaMessageId: Buffer -} diff --git a/dlt-database/entity/0001-init_db/Migration.ts b/dlt-database/entity/0001-init_db/Migration.ts deleted file mode 100644 index f1163cfbc..000000000 --- a/dlt-database/entity/0001-init_db/Migration.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' - -@Entity('migrations') -export class Migration extends BaseEntity { - @PrimaryGeneratedColumn() // This is actually not a primary column - version: number - - @Column({ length: 256, nullable: true, default: null }) - fileName: string - - @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) - date: Date -} diff --git a/dlt-database/entity/0001-init_db/TransactionRecipe.ts b/dlt-database/entity/0001-init_db/TransactionRecipe.ts deleted file mode 100644 index b2acbba75..000000000 --- a/dlt-database/entity/0001-init_db/TransactionRecipe.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - OneToOne, - JoinColumn, - BaseEntity, -} from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -// the relation in future account don't match which this any longer, so we can only link with the local account here -import { Account } from './Account' -// the relation in future community don't match which this any longer, so we can only link with the local account here -import { Community } from './Community' -// ConfirmedTransaction was removed in newer migrations, so only the version from this folder can be linked -import { ConfirmedTransaction } from './ConfirmedTransaction' - -@Entity('transaction_recipes') -export class TransactionRecipe extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true }) - iotaMessageId?: Buffer - - // if transaction has a sender than it is also the sender account - @ManyToOne(() => Account, (account) => account.transactionRecipesSigning) - @JoinColumn({ name: 'signing_account_id' }) - signingAccount: Account - - @Column({ name: 'signing_account_id', type: 'int', unsigned: true }) - signingAccountId: number - - @ManyToOne(() => Account, (account) => account.transactionRecipesRecipient) - @JoinColumn({ name: 'recipient_account_id' }) - recipientAccount?: Account - - @Column({ name: 'recipient_account_id', type: 'int', unsigned: true, nullable: true }) - recipientAccountId?: number - - @ManyToOne(() => Community, (community) => community.transactionRecipesSender) - @JoinColumn({ name: 'sender_community_id' }) - senderCommunity: Community - - @Column({ name: 'sender_community_id', type: 'int', unsigned: true }) - senderCommunityId: number - - @ManyToOne(() => Community, (community) => community.transactionRecipesRecipient) - @JoinColumn({ name: 'recipient_community_id' }) - recipientCommunity?: Community - - @Column({ name: 'recipient_community_id', type: 'int', unsigned: true, nullable: true }) - recipientCommunityId?: number - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - amount?: Decimal - - @Column({ type: 'tinyint' }) - type: number - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - @Column({ name: 'body_bytes', type: 'blob' }) - bodyBytes: Buffer - - @Column({ type: 'binary', length: 64 }) - signature: Buffer - - @Column({ name: 'protocol_version', type: 'int', default: 1 }) - protocolVersion: number - - @OneToOne(() => ConfirmedTransaction, (transaction) => transaction.transactionRecipe) - confirmedTransaction?: ConfirmedTransaction -} diff --git a/dlt-database/entity/0001-init_db/User.ts b/dlt-database/entity/0001-init_db/User.ts deleted file mode 100644 index 681a668e2..000000000 --- a/dlt-database/entity/0001-init_db/User.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany, JoinColumn } from 'typeorm' - -import { Account } from '../Account' - -@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class User extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ - name: 'gradido_id', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - gradidoID?: string - - @Column({ name: 'derive1_pubkey', type: 'binary', length: 32, unique: true }) - derive1Pubkey: Buffer - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ - name: 'confirmed_at', - type: 'datetime', - precision: 3, - nullable: true, - }) - confirmedAt?: Date - - @OneToMany(() => Account, (account) => account.user) - @JoinColumn({ name: 'user_id' }) - accounts?: Account[] -} diff --git a/dlt-database/entity/0002-refactor_add_community/Account.ts b/dlt-database/entity/0002-refactor_add_community/Account.ts deleted file mode 100644 index 821b75e73..000000000 --- a/dlt-database/entity/0002-refactor_add_community/Account.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - JoinColumn, - OneToMany, - BaseEntity, -} from 'typeorm' -import { User } from '../User' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from '../0001-init_db/TransactionRecipe' -// ConfirmedTransaction was removed in newer migrations, so only the version from this folder can be linked -import { ConfirmedTransaction } from './ConfirmedTransaction' -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Decimal } from 'decimal.js-light' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('accounts') -export class Account extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @ManyToOne(() => User, (user) => user.accounts) // Assuming you have a User entity with 'accounts' relation - @JoinColumn({ name: 'user_id' }) - user?: User - - // if user id is null, account belongs to community gmw or auf - @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true }) - userId?: number - - @Column({ name: 'derivation_index', type: 'int', unsigned: true }) - derivationIndex: number - - @Column({ name: 'derive2_pubkey', type: 'binary', length: 32, unique: true }) - derive2Pubkey: Buffer - - @Column({ type: 'tinyint', unsigned: true }) - type: number - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - default: 0, - transformer: DecimalTransformer, - }) - balance: Decimal - - @Column({ - name: 'balance_date', - type: 'datetime', - default: () => 'CURRENT_TIMESTAMP()', - }) - balanceDate: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.account) - @JoinColumn({ name: 'account_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.signingAccount) - transactionRecipesSigning?: TransactionRecipe[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.recipientAccount) - transactionRecipesRecipient?: TransactionRecipe[] - - @OneToMany(() => ConfirmedTransaction, (transaction) => transaction.account) - confirmedTransactions?: ConfirmedTransaction[] -} diff --git a/dlt-database/entity/0002-refactor_add_community/AccountCommunity.ts b/dlt-database/entity/0002-refactor_add_community/AccountCommunity.ts deleted file mode 100644 index 80d6c15bf..000000000 --- a/dlt-database/entity/0002-refactor_add_community/AccountCommunity.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, BaseEntity } from 'typeorm' - -import { Account } from '../Account' -import { Community } from '../Community' - -@Entity('accounts_communities') -export class AccountCommunity extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @ManyToOne(() => Account, (account) => account.accountCommunities) - @JoinColumn({ name: 'account_id' }) - account: Account - - @Column({ name: 'account_id', type: 'int', unsigned: true }) - accountId: number - - @ManyToOne(() => Community, (community) => community.accountCommunities) - @JoinColumn({ name: 'community_id' }) - community: Community - - @Column({ name: 'community_id', type: 'int', unsigned: true }) - communityId: number - - @Column({ name: 'valid_from', type: 'datetime' }) - validFrom: Date - - @Column({ name: 'valid_to', type: 'datetime', nullable: true }) - validTo?: Date -} diff --git a/dlt-database/entity/0002-refactor_add_community/Community.ts b/dlt-database/entity/0002-refactor_add_community/Community.ts deleted file mode 100644 index 7136efa2e..000000000 --- a/dlt-database/entity/0002-refactor_add_community/Community.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - JoinColumn, - OneToOne, - OneToMany, - BaseEntity, -} from 'typeorm' -import { Account } from '../Account' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from '../0001-init_db/TransactionRecipe' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('communities') -export class Community extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'iota_topic', collation: 'utf8mb4_unicode_ci' }) - iotaTopic: string - - @Column({ name: 'root_pubkey', type: 'binary', length: 32, unique: true, nullable: true }) - rootPubkey?: Buffer - - @Column({ name: 'root_privkey', type: 'binary', length: 64, nullable: true }) - rootPrivkey?: Buffer - - @Column({ name: 'root_chaincode', type: 'binary', length: 32, nullable: true }) - rootChaincode?: Buffer - - @Column({ type: 'tinyint', default: true }) - foreign: boolean - - @Column({ name: 'gmw_account_id', type: 'int', unsigned: true, nullable: true }) - gmwAccountId?: number - - @OneToOne(() => Account) - @JoinColumn({ name: 'gmw_account_id' }) - gmwAccount?: Account - - @Column({ name: 'auf_account_id', type: 'int', unsigned: true, nullable: true }) - aufAccountId?: number - - @OneToOne(() => Account) - @JoinColumn({ name: 'auf_account_id' }) - aufAccount?: Account - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.community) - @JoinColumn({ name: 'community_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.senderCommunity) - transactionRecipesSender?: TransactionRecipe[] - - @OneToMany(() => TransactionRecipe, (recipe) => recipe.recipientCommunity) - transactionRecipesRecipient?: TransactionRecipe[] -} diff --git a/dlt-database/entity/0002-refactor_add_community/ConfirmedTransaction.ts b/dlt-database/entity/0002-refactor_add_community/ConfirmedTransaction.ts deleted file mode 100644 index 1cdc591bf..000000000 --- a/dlt-database/entity/0002-refactor_add_community/ConfirmedTransaction.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - JoinColumn, - OneToOne, - BaseEntity, -} from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -// the relation in future account don't match which this any longer, so we can only link with the local account here -import { Account } from './Account' -// TransactionRecipe was removed in newer migrations, so only the version from this folder can be linked -import { TransactionRecipe } from '../0001-init_db/TransactionRecipe' - -@Entity('confirmed_transactions') -export class ConfirmedTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @OneToOne(() => TransactionRecipe, (recipe) => recipe.confirmedTransaction) - @JoinColumn({ name: 'transaction_recipe_id' }) - transactionRecipe: TransactionRecipe - - @Column({ name: 'transaction_recipe_id', type: 'int', unsigned: true }) - transactionRecipeId: number - - @Column({ type: 'bigint' }) - nr: number - - @Column({ type: 'binary', length: 48 }) - runningHash: Buffer - - @ManyToOne(() => Account, (account) => account.confirmedTransactions) - @JoinColumn({ name: 'account_id' }) - account: Account - - @Column({ name: 'account_id', type: 'int', unsigned: true }) - accountId: number - - @Column({ - name: 'account_balance', - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - default: 0, - transformer: DecimalTransformer, - }) - accountBalance: Decimal - - @Column({ name: 'iota_milestone', type: 'bigint' }) - iotaMilestone: number - - @Column({ name: 'confirmed_at', type: 'datetime' }) - confirmedAt: Date -} diff --git a/dlt-database/entity/0002-refactor_add_community/User.ts b/dlt-database/entity/0002-refactor_add_community/User.ts deleted file mode 100644 index 5387be058..000000000 --- a/dlt-database/entity/0002-refactor_add_community/User.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany, JoinColumn } from 'typeorm' - -import { Account } from '../Account' - -@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class User extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ - name: 'gradido_id', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - gradidoID?: string - - @Column({ name: 'derive1_pubkey', type: 'binary', length: 32, unique: true }) - derive1Pubkey: Buffer - - @Column({ - name: 'created_at', - type: 'datetime', - precision: 3, - default: () => 'CURRENT_TIMESTAMP(3)', - }) - createdAt: Date - - @Column({ - name: 'confirmed_at', - type: 'datetime', - nullable: true, - }) - confirmedAt?: Date - - @OneToMany(() => Account, (account) => account.user) - @JoinColumn({ name: 'user_id' }) - accounts?: Account[] -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/Account.ts b/dlt-database/entity/0003-refactor_transaction_recipe/Account.ts deleted file mode 100644 index 1c01094f1..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/Account.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - JoinColumn, - OneToMany, - BaseEntity, -} from 'typeorm' -import { User } from '../User' -import { Transaction } from '../Transaction' -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Decimal } from 'decimal.js-light' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('accounts') -export class Account extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @ManyToOne(() => User, (user) => user.accounts, { cascade: ['insert', 'update'], eager: true }) // Assuming you have a User entity with 'accounts' relation - @JoinColumn({ name: 'user_id' }) - user?: User - - // if user id is null, account belongs to community gmw or auf - @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true }) - userId?: number - - @Column({ name: 'derivation_index', type: 'int', unsigned: true }) - derivationIndex: number - - @Column({ name: 'derive2_pubkey', type: 'binary', length: 32, unique: true }) - derive2Pubkey: Buffer - - @Column({ type: 'tinyint', unsigned: true }) - type: number - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @Column({ - name: 'balance_on_confirmation', - type: 'decimal', - precision: 40, - scale: 20, - default: 0, - transformer: DecimalTransformer, - }) - balanceOnConfirmation: Decimal - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ - name: 'balance_confirmed_at', - type: 'datetime', - nullable: true, - }) - balanceConfirmedAt: Date - - @Column({ - name: 'balance_on_creation', - type: 'decimal', - precision: 40, - scale: 20, - default: 0, - transformer: DecimalTransformer, - }) - balanceOnCreation: Decimal - - @Column({ - name: 'balance_created_at', - type: 'datetime', - precision: 3, - }) - balanceCreatedAt: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.account) - @JoinColumn({ name: 'account_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => Transaction, (transaction) => transaction.signingAccount) - transactionSigning?: Transaction[] - - @OneToMany(() => Transaction, (transaction) => transaction.recipientAccount) - transactionRecipient?: Transaction[] -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts b/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts deleted file mode 100644 index 77744a6d4..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/BackendTransaction.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, ManyToOne, JoinColumn } from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked -import { Transaction } from './Transaction' - -@Entity('backend_transactions') -export class BackendTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'backend_transaction_id', type: 'bigint', unsigned: true, unique: true }) - backendTransactionId: number - - @ManyToOne(() => Transaction, (transaction) => transaction.backendTransactions) - @JoinColumn({ name: 'transaction_id' }) - transaction: Transaction - - @Column({ name: 'transaction_id', type: 'bigint', unsigned: true }) - transactionId: number - - @Column({ name: 'type_id', unsigned: true, nullable: false }) - typeId: number - - // account balance based on creation date - @Column({ - name: 'balance', - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - balance?: Decimal - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @Column({ name: 'verifiedOnBackend', type: 'tinyint', default: false }) - verifiedOnBackend: boolean -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/Community.ts b/dlt-database/entity/0003-refactor_transaction_recipe/Community.ts deleted file mode 100644 index 1233d0832..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/Community.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - JoinColumn, - OneToOne, - OneToMany, - BaseEntity, -} from 'typeorm' -import { Account } from '../Account' -import { Transaction } from '../Transaction' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('communities') -export class Community extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'iota_topic', collation: 'utf8mb4_unicode_ci', unique: true }) - iotaTopic: string - - @Column({ name: 'root_pubkey', type: 'binary', length: 32, unique: true, nullable: true }) - rootPubkey?: Buffer - - @Column({ name: 'root_privkey', type: 'binary', length: 64, nullable: true }) - rootPrivkey?: Buffer - - @Column({ name: 'root_chaincode', type: 'binary', length: 32, nullable: true }) - rootChaincode?: Buffer - - @Column({ type: 'tinyint', default: true }) - foreign: boolean - - @Column({ name: 'gmw_account_id', type: 'int', unsigned: true, nullable: true }) - gmwAccountId?: number - - @OneToOne(() => Account, { cascade: true }) - @JoinColumn({ name: 'gmw_account_id' }) - gmwAccount?: Account - - @Column({ name: 'auf_account_id', type: 'int', unsigned: true, nullable: true }) - aufAccountId?: number - - @OneToOne(() => Account, { cascade: true }) - @JoinColumn({ name: 'auf_account_id' }) - aufAccount?: Account - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.community) - @JoinColumn({ name: 'community_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => Transaction, (transaction) => transaction.community) - transactions?: Transaction[] - - @OneToMany(() => Transaction, (transaction) => transaction.otherCommunity) - friendCommunitiesTransactions?: Transaction[] -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/InvalidTransaction.ts b/dlt-database/entity/0003-refactor_transaction_recipe/InvalidTransaction.ts deleted file mode 100644 index a34823dbd..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/InvalidTransaction.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm' - -@Entity('invalid_transactions') -export class InvalidTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32, unique: true }) - iotaMessageId: Buffer - - @Column({ name: 'error_message', type: 'varchar', length: 255 }) - errorMessage: string -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts b/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts deleted file mode 100644 index b520b27f8..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/Transaction.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - OneToOne, - JoinColumn, - BaseEntity, - OneToMany, -} from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Account } from '../Account' -import { Community } from '../Community' -// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked -import { BackendTransaction } from './BackendTransaction' - -@Entity('transactions') -export class Transaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true }) - iotaMessageId?: Buffer - - @OneToOne(() => Transaction, { cascade: ['update'] }) - // eslint-disable-next-line no-use-before-define - paringTransaction?: Transaction - - @Column({ name: 'paring_transaction_id', type: 'bigint', unsigned: true, nullable: true }) - paringTransactionId?: number - - // if transaction has a sender than it is also the sender account - @ManyToOne(() => Account, (account) => account.transactionSigning) - @JoinColumn({ name: 'signing_account_id' }) - signingAccount?: Account - - @Column({ name: 'signing_account_id', type: 'int', unsigned: true, nullable: true }) - signingAccountId?: number - - @ManyToOne(() => Account, (account) => account.transactionRecipient) - @JoinColumn({ name: 'recipient_account_id' }) - recipientAccount?: Account - - @Column({ name: 'recipient_account_id', type: 'int', unsigned: true, nullable: true }) - recipientAccountId?: number - - @ManyToOne(() => Community, (community) => community.transactions, { - eager: true, - }) - @JoinColumn({ name: 'community_id' }) - community: Community - - @Column({ name: 'community_id', type: 'int', unsigned: true }) - communityId: number - - @ManyToOne(() => Community, (community) => community.friendCommunitiesTransactions) - @JoinColumn({ name: 'other_community_id' }) - otherCommunity?: Community - - @Column({ name: 'other_community_id', type: 'int', unsigned: true, nullable: true }) - otherCommunityId?: number - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - amount?: Decimal - - // account balance for sender based on creation date - @Column({ - name: 'account_balance_on_creation', - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - accountBalanceOnCreation?: Decimal - - @Column({ type: 'tinyint' }) - type: number - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - @Column({ name: 'body_bytes', type: 'blob' }) - bodyBytes: Buffer - - @Column({ type: 'binary', length: 64, unique: true }) - signature: Buffer - - @Column({ name: 'protocol_version', type: 'varchar', length: 255, default: '1' }) - protocolVersion: string - - @Column({ type: 'bigint', nullable: true }) - nr?: number - - @Column({ name: 'running_hash', type: 'binary', length: 48, nullable: true }) - runningHash?: Buffer - - // account balance for sender based on confirmation date (iota milestone) - @Column({ - name: 'account_balance_on_confirmation', - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - accountBalanceOnConfirmation?: Decimal - - @Column({ name: 'iota_milestone', type: 'bigint', nullable: true }) - iotaMilestone?: number - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @OneToMany(() => BackendTransaction, (backendTransaction) => backendTransaction.transaction, { - cascade: ['insert', 'update'], - }) - @JoinColumn({ name: 'transaction_id' }) - backendTransactions: BackendTransaction[] -} diff --git a/dlt-database/entity/0003-refactor_transaction_recipe/User.ts b/dlt-database/entity/0003-refactor_transaction_recipe/User.ts deleted file mode 100644 index fdfeb9830..000000000 --- a/dlt-database/entity/0003-refactor_transaction_recipe/User.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany, JoinColumn } from 'typeorm' - -import { Account } from '../Account' - -@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class User extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ - name: 'gradido_id', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - gradidoID?: string - - @Column({ name: 'derive1_pubkey', type: 'binary', length: 32, unique: true }) - derive1Pubkey: Buffer - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ - name: 'confirmed_at', - type: 'datetime', - nullable: true, - }) - confirmedAt?: Date - - @OneToMany(() => Account, (account) => account.user) - @JoinColumn({ name: 'user_id' }) - accounts?: Account[] -} diff --git a/dlt-database/entity/0004-fix_spelling/Transaction.ts b/dlt-database/entity/0004-fix_spelling/Transaction.ts deleted file mode 100644 index f3f4427f7..000000000 --- a/dlt-database/entity/0004-fix_spelling/Transaction.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - OneToOne, - JoinColumn, - BaseEntity, - OneToMany, -} from 'typeorm' -import { Decimal } from 'decimal.js-light' - -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Account } from '../Account' -import { Community } from '../Community' -// BackendTransaction was removed in newer migrations, so only the version from this folder can be linked -import { BackendTransaction } from '../0003-refactor_transaction_recipe/BackendTransaction' - -@Entity('transactions') -export class Transaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true }) - iotaMessageId?: Buffer - - @OneToOne(() => Transaction, { cascade: ['update'] }) - // eslint-disable-next-line no-use-before-define - pairingTransaction?: Transaction - - @Column({ name: 'pairing_transaction_id', type: 'bigint', unsigned: true, nullable: true }) - pairingTransactionId?: number - - // if transaction has a sender than it is also the sender account - @ManyToOne(() => Account, (account) => account.transactionSigning) - @JoinColumn({ name: 'signing_account_id' }) - signingAccount?: Account - - @Column({ name: 'signing_account_id', type: 'int', unsigned: true, nullable: true }) - signingAccountId?: number - - @ManyToOne(() => Account, (account) => account.transactionRecipient) - @JoinColumn({ name: 'recipient_account_id' }) - recipientAccount?: Account - - @Column({ name: 'recipient_account_id', type: 'int', unsigned: true, nullable: true }) - recipientAccountId?: number - - @ManyToOne(() => Community, (community) => community.transactions, { - eager: true, - }) - @JoinColumn({ name: 'community_id' }) - community: Community - - @Column({ name: 'community_id', type: 'int', unsigned: true }) - communityId: number - - @ManyToOne(() => Community, (community) => community.friendCommunitiesTransactions) - @JoinColumn({ name: 'other_community_id' }) - otherCommunity?: Community - - @Column({ name: 'other_community_id', type: 'int', unsigned: true, nullable: true }) - otherCommunityId?: number - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - amount?: Decimal - - // account balance for sender based on creation date - @Column({ - name: 'account_balance_on_creation', - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - accountBalanceOnCreation?: Decimal - - @Column({ type: 'tinyint' }) - type: number - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - @Column({ name: 'body_bytes', type: 'blob' }) - bodyBytes: Buffer - - @Column({ type: 'binary', length: 64, unique: true }) - signature: Buffer - - @Column({ name: 'protocol_version', type: 'varchar', length: 255, default: '1' }) - protocolVersion: string - - @Column({ type: 'bigint', nullable: true }) - nr?: number - - @Column({ name: 'running_hash', type: 'binary', length: 48, nullable: true }) - runningHash?: Buffer - - // account balance for sender based on confirmation date (iota milestone) - @Column({ - name: 'account_balance_on_confirmation', - type: 'decimal', - precision: 40, - scale: 20, - nullable: true, - transformer: DecimalTransformer, - }) - accountBalanceOnConfirmation?: Decimal - - @Column({ name: 'iota_milestone', type: 'bigint', nullable: true }) - iotaMilestone?: number - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @OneToMany(() => BackendTransaction, (backendTransaction) => backendTransaction.transaction, { - cascade: ['insert', 'update'], - }) - @JoinColumn({ name: 'transaction_id' }) - backendTransactions: BackendTransaction[] -} diff --git a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts deleted file mode 100644 index f19790ff1..000000000 --- a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Community.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - JoinColumn, - OneToOne, - OneToMany, - BaseEntity, -} from 'typeorm' -import { Account } from '../Account' -import { Transaction } from '../Transaction' -import { AccountCommunity } from '../AccountCommunity' - -@Entity('communities') -export class Community extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'iota_topic', collation: 'utf8mb4_unicode_ci', unique: true }) - iotaTopic: string - - @Column({ name: 'root_pubkey', type: 'binary', length: 32, unique: true, nullable: true }) - rootPubkey?: Buffer - - @Column({ name: 'root_privkey', type: 'binary', length: 80, nullable: true }) - rootEncryptedPrivkey?: Buffer - - @Column({ name: 'root_chaincode', type: 'binary', length: 32, nullable: true }) - rootChaincode?: Buffer - - @Column({ type: 'tinyint', default: true }) - foreign: boolean - - @Column({ name: 'gmw_account_id', type: 'int', unsigned: true, nullable: true }) - gmwAccountId?: number - - @OneToOne(() => Account, { cascade: true }) - @JoinColumn({ name: 'gmw_account_id' }) - gmwAccount?: Account - - @Column({ name: 'auf_account_id', type: 'int', unsigned: true, nullable: true }) - aufAccountId?: number - - @OneToOne(() => Account, { cascade: true }) - @JoinColumn({ name: 'auf_account_id' }) - aufAccount?: Account - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date - - @OneToMany(() => AccountCommunity, (accountCommunity) => accountCommunity.community) - @JoinColumn({ name: 'community_id' }) - accountCommunities: AccountCommunity[] - - @OneToMany(() => Transaction, (transaction) => transaction.community) - transactions?: Transaction[] - - @OneToMany(() => Transaction, (transaction) => transaction.otherCommunity) - friendCommunitiesTransactions?: Transaction[] -} diff --git a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts b/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts deleted file mode 100644 index eae5a6405..000000000 --- a/dlt-database/entity/0005-refactor_with_gradido_blockchain_lib/Transaction.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - ManyToOne, - OneToOne, - JoinColumn, - BaseEntity, -} from 'typeorm' - -import { Account } from '../Account' -import { Community } from '../Community' - -@Entity('transactions') -export class Transaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true, type: 'bigint' }) - id: number - - @Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true }) - iotaMessageId?: Buffer - - @OneToOne(() => Transaction, { cascade: ['update'] }) - // eslint-disable-next-line no-use-before-define - pairingTransaction?: Transaction - - @Column({ name: 'pairing_transaction_id', type: 'bigint', unsigned: true, nullable: true }) - pairingTransactionId?: number - - // if transaction has a sender than it is also the sender account - @ManyToOne(() => Account, (account) => account.transactionSigning) - @JoinColumn({ name: 'signing_account_id' }) - signingAccount?: Account - - @Column({ name: 'signing_account_id', type: 'int', unsigned: true, nullable: true }) - signingAccountId?: number - - @ManyToOne(() => Account, (account) => account.transactionRecipient) - @JoinColumn({ name: 'recipient_account_id' }) - recipientAccount?: Account - - @Column({ name: 'recipient_account_id', type: 'int', unsigned: true, nullable: true }) - recipientAccountId?: number - - @ManyToOne(() => Community, (community) => community.transactions, { - eager: true, - }) - @JoinColumn({ name: 'community_id' }) - community: Community - - @Column({ name: 'community_id', type: 'int', unsigned: true }) - communityId: number - - @ManyToOne(() => Community, (community) => community.friendCommunitiesTransactions) - @JoinColumn({ name: 'other_community_id' }) - otherCommunity?: Community - - @Column({ name: 'other_community_id', type: 'int', unsigned: true, nullable: true }) - otherCommunityId?: number - - @Column({ - type: 'bigint', - nullable: true, - }) - amount?: number - - // account balance for sender based on creation date - @Column({ - name: 'account_balance_on_creation', - type: 'bigint', - nullable: true, - }) - accountBalanceOnCreation?: number - - @Column({ type: 'tinyint' }) - type: number - - @Column({ name: 'created_at', type: 'datetime', precision: 3 }) - createdAt: Date - - @Column({ name: 'body_bytes', type: 'blob' }) - bodyBytes: Buffer - - @Column({ type: 'binary', length: 64, unique: true }) - signature: Buffer - - @Column({ name: 'protocol_version', type: 'varchar', length: 255, default: '1' }) - protocolVersion: string - - @Column({ type: 'bigint', nullable: true }) - nr?: number - - @Column({ name: 'running_hash', type: 'binary', length: 48, nullable: true }) - runningHash?: Buffer - - // account balance for sender based on confirmation date (iota milestone) - @Column({ - name: 'account_balance_on_confirmation', - type: 'bigint', - nullable: true, - }) - accountBalanceOnConfirmation?: number - - @Column({ name: 'iota_milestone', type: 'bigint', nullable: true }) - iotaMilestone?: number - - // use timestamp from iota milestone which is only in seconds precision, so no need to use 3 Bytes extra here - @Column({ name: 'confirmed_at', type: 'datetime', nullable: true }) - confirmedAt?: Date -} diff --git a/dlt-database/entity/Account.ts b/dlt-database/entity/Account.ts deleted file mode 100644 index 3d7713ba9..000000000 --- a/dlt-database/entity/Account.ts +++ /dev/null @@ -1 +0,0 @@ -export { Account } from './0003-refactor_transaction_recipe/Account' diff --git a/dlt-database/entity/AccountCommunity.ts b/dlt-database/entity/AccountCommunity.ts deleted file mode 100644 index 985e7bfb9..000000000 --- a/dlt-database/entity/AccountCommunity.ts +++ /dev/null @@ -1 +0,0 @@ -export { AccountCommunity } from './0002-refactor_add_community/AccountCommunity' diff --git a/dlt-database/entity/Community.ts b/dlt-database/entity/Community.ts deleted file mode 100644 index e31bb1e5a..000000000 --- a/dlt-database/entity/Community.ts +++ /dev/null @@ -1 +0,0 @@ -export { Community } from './0005-refactor_with_gradido_blockchain_lib/Community' diff --git a/dlt-database/entity/InvalidTransaction.ts b/dlt-database/entity/InvalidTransaction.ts deleted file mode 100644 index 166b13adf..000000000 --- a/dlt-database/entity/InvalidTransaction.ts +++ /dev/null @@ -1 +0,0 @@ -export { InvalidTransaction } from './0003-refactor_transaction_recipe/InvalidTransaction' diff --git a/dlt-database/entity/Migration.ts b/dlt-database/entity/Migration.ts deleted file mode 100644 index 9f1e743d0..000000000 --- a/dlt-database/entity/Migration.ts +++ /dev/null @@ -1 +0,0 @@ -export { Migration } from './0001-init_db/Migration' diff --git a/dlt-database/entity/Transaction.ts b/dlt-database/entity/Transaction.ts deleted file mode 100644 index 4c22b275f..000000000 --- a/dlt-database/entity/Transaction.ts +++ /dev/null @@ -1 +0,0 @@ -export { Transaction } from './0005-refactor_with_gradido_blockchain_lib/Transaction' diff --git a/dlt-database/entity/User.ts b/dlt-database/entity/User.ts deleted file mode 100644 index 4f1b039ff..000000000 --- a/dlt-database/entity/User.ts +++ /dev/null @@ -1 +0,0 @@ -export { User } from './0003-refactor_transaction_recipe/User' diff --git a/dlt-database/entity/index.ts b/dlt-database/entity/index.ts deleted file mode 100644 index ba7ea2663..000000000 --- a/dlt-database/entity/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Account } from './Account' -import { AccountCommunity } from './AccountCommunity' -import { Community } from './Community' -import { InvalidTransaction } from './InvalidTransaction' -import { Migration } from './Migration' -import { Transaction } from './Transaction' -import { User } from './User' - -export const entities = [ - AccountCommunity, - Account, - Community, - InvalidTransaction, - Migration, - Transaction, - User, -] diff --git a/dlt-database/log/.gitignore b/dlt-database/log/.gitignore deleted file mode 100644 index c96a04f00..000000000 --- a/dlt-database/log/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/dlt-database/migrations/0001-init_db.ts b/dlt-database/migrations/0001-init_db.ts deleted file mode 100644 index 8188a889d..000000000 --- a/dlt-database/migrations/0001-init_db.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* FIRST MIGRATION - * - * This migration is special since it takes into account that - * the database can be setup already but also may not be. - * Therefore you will find all `CREATE TABLE` statements with - * a `IF NOT EXISTS`, all `INSERT` with an `IGNORE` and in the - * downgrade function all `DROP TABLE` with a `IF EXISTS`. - * This ensures compatibility for existing or non-existing - * databases. - */ - -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - // write upgrade logic as parameter of queryFn - await queryFn(` - CREATE TABLE IF NOT EXISTS \`users\` ( - \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, - \`gradido_id\` char(36) DEFAULT NULL, - \`derive1_pubkey\` binary(32) NOT NULL, - \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - \`confirmed_at\` datetime(3) DEFAULT NULL, - PRIMARY KEY (\`id\`), - INDEX \`gradido_id\` (\`gradido_id\`), - UNIQUE KEY \`derive1_pubkey\` (\`derive1_pubkey\`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`accounts\` ( - \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, - \`user_id\` int(10) unsigned DEFAULT NULL, - \`derivation_index\` int(10) unsigned NOT NULL, - \`derive2_pubkey\` binary(32) NOT NULL, - \`type\` tinyint unsigned NOT NULL, - \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - \`confirmed_at\` datetime(3) DEFAULT NULL, - \`balance\` decimal(40,20) NOT NULL DEFAULT 0, - \`balance_date\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - PRIMARY KEY (\`id\`), - UNIQUE KEY \`derive2_pubkey\` (\`derive2_pubkey\`), - FOREIGN KEY (\`user_id\`) REFERENCES users(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - `) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`communities\` ( - \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, - \`iota_topic\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - \`root_pubkey\` binary(32) NOT NULL, - \`root_privkey\` binary(32) DEFAULT NULL, - \`root_chaincode\` binary(32) DEFAULT NULL, - \`foreign\` tinyint(4) NOT NULL DEFAULT true, - \`gmw_account_id\` int(10) unsigned DEFAULT NULL, - \`auf_account_id\` int(10) unsigned DEFAULT NULL, - \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - \`confirmed_at\` datetime(3) DEFAULT NULL, - PRIMARY KEY (\`id\`), - UNIQUE KEY \`root_pubkey\` (\`root_pubkey\`), - FOREIGN KEY (\`gmw_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`auf_account_id\`) REFERENCES accounts(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`accounts_communities\` ( - \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, - \`account_id\` int(10) unsigned NOT NULL, - \`community_id\` int(10) unsigned NOT NULL, - \`valid_from\` datetime(3) NOT NULL, - \`valid_to\` datetime(3) DEFAULT NULL, - PRIMARY KEY (\`id\`), - FOREIGN KEY (\`account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`community_id\`) REFERENCES communities(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`transaction_recipes\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`iota_message_id\` binary(32) DEFAULT NULL, - \`signing_account_id\` int(10) unsigned NOT NULL, - \`recipient_account_id\` int(10) unsigned DEFAULT NULL, - \`sender_community_id\` int(10) unsigned NOT NULL, - \`recipient_community_id\` int(10) unsigned DEFAULT NULL, - \`amount\` decimal(40,20) DEFAULT NULL, - \`type\` tinyint unsigned NOT NULL, - \`created_at\` datetime(3) NOT NULL, - \`body_bytes\` BLOB NOT NULL, - \`signature\` binary(64) NOT NULL, - \`protocol_version\` int(10) NOT NULL DEFAULT 1, - PRIMARY KEY (\`id\`), - FOREIGN KEY (\`signing_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`recipient_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`sender_community_id\`) REFERENCES communities(id), - FOREIGN KEY (\`recipient_community_id\`) REFERENCES communities(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`confirmed_transactions\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`transaction_recipe_id\` bigint unsigned NOT NULL, - \`nr\` bigint unsigned NOT NULL, - \`running_hash\` binary(48) NOT NULL, - \`account_id\` int(10) unsigned NOT NULL, - \`account_balance\` decimal(40,20) NOT NULL DEFAULT 0, - \`iota_milestone\` bigint NOT NULL, - \`confirmed_at\` datetime(3) NOT NULL, - PRIMARY KEY (\`id\`), - FOREIGN KEY (\`transaction_recipe_id\`) REFERENCES transaction_recipes(id), - FOREIGN KEY (\`account_id\`) REFERENCES accounts(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`invalid_transactions\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`iota_message_id\` binary(32) NOT NULL, - PRIMARY KEY (\`id\`), - INDEX (\`iota_message_id\`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - // write downgrade logic as parameter of queryFn - await queryFn(`DROP TABLE IF EXISTS \`users\`;`) - await queryFn(`DROP TABLE IF EXISTS \`accounts\`;`) - await queryFn(`DROP TABLE IF EXISTS \`accounts_communities\`;`) - await queryFn(`DROP TABLE IF EXISTS \`transaction_recipes\`;`) - await queryFn(`DROP TABLE IF EXISTS \`confirmed_transactions\`;`) - await queryFn(`DROP TABLE IF EXISTS \`communities\`;`) - await queryFn(`DROP TABLE IF EXISTS \`invalid_transactions\`;`) -} diff --git a/dlt-database/migrations/0002-refactor_add_community.ts b/dlt-database/migrations/0002-refactor_add_community.ts deleted file mode 100644 index 725954ea0..000000000 --- a/dlt-database/migrations/0002-refactor_add_community.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - // write upgrade logic as parameter of queryFn - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`root_privkey\` binary(64) NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`root_pubkey\` binary(32) NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`root_chaincode\` binary(32) NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`confirmed_at\` datetime NULL DEFAULT NULL;`, - ) - await queryFn(`ALTER TABLE \`users\` MODIFY COLUMN \`confirmed_at\` datetime NULL DEFAULT NULL;`) - await queryFn( - `ALTER TABLE \`accounts\` MODIFY COLUMN \`confirmed_at\` datetime NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`accounts\` MODIFY COLUMN \`balance_date\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;`, - ) - await queryFn( - `ALTER TABLE \`accounts_communities\` MODIFY COLUMN \`valid_from\` datetime NOT NULL;`, - ) - await queryFn( - `ALTER TABLE \`accounts_communities\` MODIFY COLUMN \`valid_to\` datetime NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`confirmed_transactions\` MODIFY COLUMN \`confirmed_at\` datetime NOT NULL;`, - ) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`root_privkey\` binary(32) DEFAULT NULL;`, - ) - await queryFn(`ALTER TABLE \`communities\` MODIFY COLUMN \`root_pubkey\` binary(32) NOT NULL;`) - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`root_chaincode\` binary(32) DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`communities\` MODIFY COLUMN \`confirmed_at\` datetime(3) DEFAULT NULL;`, - ) - await queryFn(`ALTER TABLE \`users\` MODIFY COLUMN \`confirmed_at\` datetime(3) DEFAULT NULL;`) - await queryFn(`ALTER TABLE \`accounts\` MODIFY COLUMN \`confirmed_at\` datetime(3) DEFAULT NULL;`) - await queryFn( - `ALTER TABLE \`accounts\` MODIFY COLUMN \`balance_date\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);`, - ) - await queryFn( - `ALTER TABLE \`accounts_communities\` MODIFY COLUMN \`valid_from\` datetime(3) NOT NULL;`, - ) - await queryFn( - `ALTER TABLE \`accounts_communities\` MODIFY COLUMN \`valid_to\` datetime(3) DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`confirmed_transactions\` MODIFY COLUMN \`confirmed_at\` datetime(3) NOT NULL;`, - ) -} diff --git a/dlt-database/migrations/0003-refactor_transaction_recipe.ts b/dlt-database/migrations/0003-refactor_transaction_recipe.ts deleted file mode 100644 index 0c022cc42..000000000 --- a/dlt-database/migrations/0003-refactor_transaction_recipe.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - // write upgrade logic as parameter of queryFn - await queryFn(`DROP TABLE \`confirmed_transactions\`;`) - await queryFn(`DROP TABLE \`transaction_recipes\`;`) - - await queryFn(` - ALTER TABLE \`accounts\` - RENAME COLUMN \`balance\` TO \`balance_on_confirmation\`, - RENAME COLUMN \`balance_date\` TO \`balance_confirmed_at\` - ; - `) - - await queryFn( - `ALTER TABLE \`accounts\` ADD COLUMN \`balance_on_creation\` decimal(40,20) NOT NULL DEFAULT 0 AFTER \`balance_confirmed_at\`;`, - ) - await queryFn( - `ALTER TABLE \`accounts\` ADD COLUMN \`balance_created_at\` datetime(3) NOT NULL AFTER \`balance_on_creation\`;`, - ) - await queryFn( - `ALTER TABLE \`accounts\` MODIFY COLUMN \`balance_confirmed_at\` datetime NULL DEFAULT NULL;`, - ) - - await queryFn( - `ALTER TABLE \`invalid_transactions\` ADD COLUMN \`error_message\` varchar(255) NOT NULL;`, - ) - - await queryFn(`ALTER TABLE \`invalid_transactions\` DROP INDEX \`iota_message_id\`;`) - await queryFn(`ALTER TABLE \`invalid_transactions\` ADD UNIQUE(\`iota_message_id\`);`) - - await queryFn( - `CREATE TABLE \`transactions\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`iota_message_id\` varbinary(32) NULL DEFAULT NULL, - \`paring_transaction_id\` bigint unsigned NULL DEFAULT NULL, - \`signing_account_id\` int unsigned NULL DEFAULT NULL, - \`recipient_account_id\` int unsigned NULL DEFAULT NULL, - \`community_id\` int unsigned NOT NULL, - \`other_community_id\` int unsigned NULL DEFAULT NULL, - \`amount\` decimal(40, 20) NULL DEFAULT NULL, - \`account_balance_on_creation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000, - \`type\` tinyint NOT NULL, - \`created_at\` datetime(3) NOT NULL, - \`body_bytes\` blob NOT NULL, - \`signature\` varbinary(64) NOT NULL, - \`protocol_version\` varchar(255) NOT NULL DEFAULT '1', - \`nr\` bigint NULL DEFAULT NULL, - \`running_hash\` varbinary(48) NULL DEFAULT NULL, - \`account_balance_on_confirmation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000, - \`iota_milestone\` bigint NULL DEFAULT NULL, - \`confirmed_at\` datetime NULL DEFAULT NULL, - PRIMARY KEY (\`id\`), - UNIQUE KEY \`signature\` (\`signature\`), - FOREIGN KEY (\`signing_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`recipient_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`community_id\`) REFERENCES communities(id), - FOREIGN KEY (\`other_community_id\`) REFERENCES communities(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - `, - ) - - await queryFn( - `CREATE TABLE \`backend_transactions\` ( - \`id\` BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, - \`backend_transaction_id\` BIGINT UNSIGNED NOT NULL, - \`transaction_id\` BIGINT UNSIGNED NOT NULL, - \`type_id\` INT UNSIGNED NOT NULL, - \`balance\` DECIMAL(40, 20) NULL DEFAULT NULL, - \`created_at\` DATETIME(3) NOT NULL, - \`confirmed_at\` DATETIME NULL DEFAULT NULL, - \`verifiedOnBackend\` TINYINT NOT NULL DEFAULT 0, - PRIMARY KEY (\`id\`), - UNIQUE (\`backend_transaction_id\`), - FOREIGN KEY (\`transaction_id\`) REFERENCES transactions(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - `, - ) - - await queryFn(`ALTER TABLE \`communities\` ADD UNIQUE(\`iota_topic\`);`) - - await queryFn(`ALTER TABLE \`users\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL;`) - await queryFn( - `ALTER TABLE \`communities\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL;`, - ) - await queryFn( - `ALTER TABLE \`accounts\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL;`, - ) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(` - CREATE TABLE IF NOT EXISTS \`transaction_recipes\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`iota_message_id\` binary(32) DEFAULT NULL, - \`signing_account_id\` int(10) unsigned NOT NULL, - \`recipient_account_id\` int(10) unsigned DEFAULT NULL, - \`sender_community_id\` int(10) unsigned NOT NULL, - \`recipient_community_id\` int(10) unsigned DEFAULT NULL, - \`amount\` decimal(40,20) DEFAULT NULL, - \`type\` tinyint unsigned NOT NULL, - \`created_at\` datetime(3) NOT NULL, - \`body_bytes\` BLOB NOT NULL, - \`signature\` binary(64) NOT NULL, - \`protocol_version\` int(10) NOT NULL DEFAULT 1, - PRIMARY KEY (\`id\`), - FOREIGN KEY (\`signing_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`recipient_account_id\`) REFERENCES accounts(id), - FOREIGN KEY (\`sender_community_id\`) REFERENCES communities(id), - FOREIGN KEY (\`recipient_community_id\`) REFERENCES communities(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn(` - CREATE TABLE IF NOT EXISTS \`confirmed_transactions\` ( - \`id\` bigint unsigned NOT NULL AUTO_INCREMENT, - \`transaction_recipe_id\` bigint unsigned NOT NULL, - \`nr\` bigint unsigned NOT NULL, - \`running_hash\` binary(48) NOT NULL, - \`account_id\` int(10) unsigned NOT NULL, - \`account_balance\` decimal(40,20) NOT NULL DEFAULT 0, - \`iota_milestone\` bigint NOT NULL, - \`confirmed_at\` datetime NOT NULL, - PRIMARY KEY (\`id\`), - FOREIGN KEY (\`transaction_recipe_id\`) REFERENCES transaction_recipes(id), - FOREIGN KEY (\`account_id\`) REFERENCES accounts(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) - - await queryFn( - `ALTER TABLE \`accounts\` MODIFY COLUMN \`balance_confirmed_at_date\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);`, - ) - await queryFn(` - ALTER TABLE \`accounts\` - RENAME COLUMN \`balance_on_confirmation\` TO \`balance\`, - RENAME COLUMN \`balance_confirmed_at\` TO \`balance_date\` - ; - `) - - await queryFn(`ALTER TABLE \`accounts\` DROP COLUMN \`balance_on_creation\`;`) - await queryFn(`ALTER TABLE \`accounts\` DROP COLUMN \`balance_created_at\`;`) - await queryFn(`ALTER TABLE \`invalid_transactions\` DROP COLUMN \`error_message\`;`) - await queryFn(`ALTER TABLE \`invalid_transactions\` DROP INDEX \`iota_message_id\`;`) - await queryFn(`ALTER TABLE \`invalid_transactions\` ADD INDEX(\`iota_message_id\`); `) - await queryFn(`DROP TABLE \`transactions\`;`) - await queryFn(`DROP TABLE \`backend_transactions\`;`) - - await queryFn( - `ALTER TABLE \`users\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);`, - ) - await queryFn( - `ALTER TABLE \`communities\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);`, - ) - await queryFn( - `ALTER TABLE \`accounts\` CHANGE \`created_at\` \`created_at\` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);`, - ) -} diff --git a/dlt-database/migrations/0004-fix_spelling.ts b/dlt-database/migrations/0004-fix_spelling.ts deleted file mode 100644 index 1507ab590..000000000 --- a/dlt-database/migrations/0004-fix_spelling.ts +++ /dev/null @@ -1,15 +0,0 @@ -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(` - ALTER TABLE \`transactions\` - RENAME COLUMN \`paring_transaction_id\` TO \`pairing_transaction_id\` - ; - `) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(` - ALTER TABLE \`transactions\` - RENAME COLUMN \`pairing_transaction_id\` TO \`paring_transaction_id\` - ; - `) -} diff --git a/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts b/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts deleted file mode 100644 index 453c131ba..000000000 --- a/dlt-database/migrations/0005-refactor_with_gradido_blockchain_lib.ts +++ /dev/null @@ -1,28 +0,0 @@ -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn( - `ALTER TABLE \`communities\` CHANGE COLUMN \`root_privkey\` \`root_encrypted_privkey\` binary(80) NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_confirmation\` int NULL DEFAULT 0;`, - ) - await queryFn( - `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_creation\` int NULL DEFAULT 0;`, - ) - await queryFn(`ALTER TABLE \`transactions\` MODIFY COLUMN \`amount\` int NULL DEFAULT 0;`) - await queryFn(`DROP TABLE \`backend_transactions\`;`) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn( - `ALTER TABLE \`communities\` CHANGE COLUMN \`root_encrypted_privkey\` \`root_privkey\` binary(64) NULL DEFAULT NULL;`, - ) - await queryFn( - `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_confirmation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000;`, - ) - await queryFn( - `ALTER TABLE \`transactions\` MODIFY COLUMN \`account_balance_on_creation\` decimal(40, 20) NULL DEFAULT 0.00000000000000000000;`, - ) - await queryFn( - `ALTER TABLE \`transactions\` MODIFY COLUMN \`amount\` decimal(40, 20) NULL DEFAULT NULL;`, - ) -} diff --git a/dlt-database/package.json b/dlt-database/package.json deleted file mode 100644 index f60587dad..000000000 --- a/dlt-database/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "gradido-database", - "version": "1.23.2", - "description": "Gradido Database Tool to execute database migrations", - "main": "src/index.ts", - "repository": "https://github.com/gradido/gradido/database", - "author": "Ulf Gebhardt", - "license": "Apache-2.0", - "private": false, - "scripts": { - "build": "tsc --build", - "clean": "tsc --build --clean", - "up": "cross-env TZ=UTC node build/src/index.js up", - "down": "cross-env TZ=UTC node build/src/index.js down", - "reset": "cross-env TZ=UTC node build/src/index.js reset", - "dev_up": "cross-env TZ=UTC ts-node src/index.ts up", - "dev_down": "cross-env TZ=UTC ts-node src/index.ts down", - "dev_reset": "cross-env TZ=UTC ts-node src/index.ts reset", - "lint": "eslint --max-warnings=0 --ext .js,.ts ." - }, - "devDependencies": { - "@eslint-community/eslint-plugin-eslint-comments": "^3.2.1", - "@types/faker": "^5.5.9", - "@types/node": "^16.10.3", - "@typescript-eslint/eslint-plugin": "^5.57.1", - "@typescript-eslint/parser": "^5.57.1", - "eslint": "^8.37.0", - "eslint-config-prettier": "^8.8.0", - "eslint-config-standard": "^17.0.0", - "eslint-import-resolver-typescript": "^3.5.4", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-security": "^1.7.1", - "prettier": "^2.8.7", - "ts-node": "^10.2.1", - "typescript": "^4.3.5" - }, - "dependencies": { - "@types/uuid": "^8.3.4", - "cross-env": "^7.0.3", - "crypto": "^1.0.1", - "decimal.js-light": "^2.5.1", - "dotenv": "^10.0.0", - "mysql2": "^2.3.0", - "reflect-metadata": "^0.1.13", - "ts-mysql-migrate": "^1.0.2", - "typeorm": "^0.3.16", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=14" - } -} diff --git a/dlt-database/src/config/index.ts b/dlt-database/src/config/index.ts deleted file mode 100644 index 46a1e580c..000000000 --- a/dlt-database/src/config/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable n/no-process-env */ - -import dotenv from 'dotenv' - -dotenv.config() - -const constants = { - CONFIG_VERSION: { - DEFAULT: 'DEFAULT', - EXPECTED: 'v1.2022-08-22', - CURRENT: '', - }, -} - -const database = { - DB_HOST: process.env.DB_HOST ?? 'localhost', - DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER ?? 'root', - DB_PASSWORD: process.env.DB_PASSWORD ?? '', - DB_DATABASE: process.env.DB_DATABASE ?? 'gradido_dlt', -} - -const migrations = { - MIGRATIONS_TABLE: process.env.MIGRATIONS_TABLE ?? 'migrations', -} - -// Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT -if ( - ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( - constants.CONFIG_VERSION.CURRENT, - ) -) { - throw new Error( - `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, - ) -} - -export const CONFIG = { ...constants, ...database, ...migrations } diff --git a/dlt-database/src/index.ts b/dlt-database/src/index.ts deleted file mode 100644 index 96785a721..000000000 --- a/dlt-database/src/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { createDatabase } from './prepare' -import { CONFIG } from './config' - -import { createPool } from 'mysql' -import { Migration } from 'ts-mysql-migrate' -import path from 'path' - -const run = async (command: string) => { - // Database actions not supported by our migration library - await createDatabase() - - // Initialize Migrations - const pool = createPool({ - host: CONFIG.DB_HOST, - port: CONFIG.DB_PORT, - user: CONFIG.DB_USER, - password: CONFIG.DB_PASSWORD, - database: CONFIG.DB_DATABASE, - }) - const migration = new Migration({ - conn: pool, - tableName: CONFIG.MIGRATIONS_TABLE, - silent: true, - dir: path.join(__dirname, '..', 'migrations'), - }) - await migration.initialize() - - // Execute command - switch (command) { - case 'up': - await migration.up() // use for upgrade script - break - case 'down': - await migration.down() // use for downgrade script - break - case 'reset': - // TODO protect from production - await migration.reset() - break - default: - throw new Error(`Unsupported command ${command}`) - } - - // Terminate connections gracefully - pool.end() -} - -run(process.argv[2]) - .catch((err) => { - // eslint-disable-next-line no-console - console.log(err) - process.exit(1) - }) - .then(() => { - process.exit() - }) diff --git a/dlt-database/src/prepare.ts b/dlt-database/src/prepare.ts deleted file mode 100644 index aa7e6d862..000000000 --- a/dlt-database/src/prepare.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createConnection } from 'mysql2/promise' - -import { CONFIG } from './config' - -export const createDatabase = async (): Promise => { - const con = await createConnection({ - host: CONFIG.DB_HOST, - port: CONFIG.DB_PORT, - user: CONFIG.DB_USER, - password: CONFIG.DB_PASSWORD, - }) - - await con.connect() - - // Create Database `gradido_dlt` - await con.query(` - CREATE DATABASE IF NOT EXISTS ${CONFIG.DB_DATABASE} - DEFAULT CHARACTER SET utf8mb4 - DEFAULT COLLATE utf8mb4_unicode_ci;`) - - await con.end() -} diff --git a/dlt-database/src/typeorm.ts b/dlt-database/src/typeorm.ts deleted file mode 100644 index 4b4f494f1..000000000 --- a/dlt-database/src/typeorm.ts +++ /dev/null @@ -1 +0,0 @@ -export * from 'typeorm' diff --git a/dlt-database/src/typeorm/DecimalTransformer.ts b/dlt-database/src/typeorm/DecimalTransformer.ts deleted file mode 100644 index b1bcb8ca3..000000000 --- a/dlt-database/src/typeorm/DecimalTransformer.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Decimal } from 'decimal.js-light' -import { ValueTransformer } from 'typeorm' - -Decimal.set({ - precision: 25, - rounding: Decimal.ROUND_HALF_UP, -}) - -export const DecimalTransformer: ValueTransformer = { - /** - * Used to marshal Decimal when writing to the database. - */ - to: (decimal: Decimal | null): string | null => (decimal ? decimal.toString() : null), - - /** - * Used to unmarshal Decimal when reading from the database. - */ - from: (decimal: string | null): Decimal | null => (decimal ? new Decimal(decimal) : null), -} diff --git a/dlt-database/tsconfig.json b/dlt-database/tsconfig.json deleted file mode 100644 index 445b9d11f..000000000 --- a/dlt-database/tsconfig.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./build/outfile.js", /* Concatenate and emit output to single file. */ - "outDir": "./build", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [".", "../database"], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* 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'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - }, - "references": [] /* Any project that is referenced must itself have a `references` array (which may be empty). */ -} diff --git a/dlt-database/yarn.lock b/dlt-database/yarn.lock deleted file mode 100644 index f4e8c4086..000000000 --- a/dlt-database/yarn.lock +++ /dev/null @@ -1,2594 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@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" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@eslint-community/eslint-plugin-eslint-comments@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.1.tgz#3c65061e27f155eae3744c3b30c5a8253a959040" - integrity sha512-/HZbjIGaVO2zLlWX3gRgiHmKRVvvqrC0zVu3eXnIj1ORxoyfGSj50l0PfDfqihyZAqrDYzSMdJesXzFjvAoiLQ== - dependencies: - escape-string-regexp "^1.0.5" - ignore "^5.2.4" - -"@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", "@eslint-community/regexpp@^4.6.1": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" - integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== - -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - 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.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== - -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.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@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@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" - -"@nolyfill/is-core-module@1.0.39": - version "1.0.39" - resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" - integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@sqltools/formatter@^1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12" - integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== - -"@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@types/faker@^5.5.9": - version "5.5.9" - resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.5.9.tgz#588ede92186dc557bff8341d294335d50d255f0c" - integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA== - -"@types/json-schema@^7.0.9": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/mysql@^2.15.8": - version "2.15.26" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" - integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== - dependencies: - "@types/node" "*" - -"@types/node@*": - version "22.5.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793" - integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg== - dependencies: - undici-types "~6.19.2" - -"@types/node@^16.10.3": - version "16.18.106" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.106.tgz#62228200da6d98365d2de5601f7230cdf041f0e2" - integrity sha512-YTgQUcpdXRc7iiEMutkkXl9WUx5lGUCVYvnfRg9CV+IA4l9epctEhCTbaw4KgzXaKYv8emvFJkEM65+MkNUhsQ== - -"@types/semver@^7.3.12": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - -"@types/uuid@^8.3.4": - version "8.3.4" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" - integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== - -"@typescript-eslint/eslint-plugin@^5.57.1": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" - integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/type-utils" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.57.1": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" - integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== - dependencies: - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" - -"@typescript-eslint/type-utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" - integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== - dependencies: - "@typescript-eslint/typescript-estree" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" - integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== - -"@typescript-eslint/typescript-estree@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.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.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - eslint-scope "^5.1.1" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" - integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== - dependencies: - "@typescript-eslint/types" "5.62.0" - eslint-visitor-keys "^3.3.0" - -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -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== - -acorn-walk@^8.1.1: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== - dependencies: - acorn "^8.11.0" - -acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - -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== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -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" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - -app-root-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" - integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -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-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-includes@^3.1.7: - version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.4" - is-string "^1.0.7" - -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== - -array.prototype.findlastindex@^1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" - integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-shim-unscopables "^1.0.2" - -array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bignumber.js@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" - integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - 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.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -builtins@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.1.0.tgz#6d85eeb360c4ebc166c3fdef922a15aa7316a5e8" - integrity sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== - dependencies: - semver "^7.0.0" - -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^4.0.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== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -cli-highlight@^2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -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" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -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" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-env@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" - integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== - dependencies: - cross-spawn "^7.0.1" - -cross-spawn@^7.0.0, cross-spawn@^7.0.1, 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: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" - integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== - -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -dayjs@^1.11.9: - version "1.11.13" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" - integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: - version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== - dependencies: - ms "2.1.2" - -decimal.js-light@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" - integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== - -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== - -define-data-property@^1.0.1, define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -denque@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" - integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== - -diff@^4.0.1: - version "4.0.2" - 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" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - -dotenv@^16.0.3: - version "16.4.5" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" - integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -enhanced-resolve@^5.15.0: - version "5.17.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" - integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.2.1, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escalade@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -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.8.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" - integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== - -eslint-config-standard@^17.0.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" - integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== - -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-import-resolver-typescript@^3.5.4: - version "3.6.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" - integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== - dependencies: - "@nolyfill/is-core-module" "1.0.39" - debug "^4.3.5" - enhanced-resolve "^5.15.0" - eslint-module-utils "^2.8.1" - fast-glob "^3.3.2" - get-tsconfig "^4.7.5" - is-bun-module "^1.0.2" - is-glob "^4.0.3" - -eslint-module-utils@^2.8.0, eslint-module-utils@^2.8.1: - version "2.8.2" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz#2ecad69d71e1fa81f17f7f24d5d3e46b168de663" - integrity sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg== - dependencies: - debug "^3.2.7" - -eslint-plugin-es@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9" - integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ== - dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" - -eslint-plugin-import@^2.27.5: - version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.15.0" - -eslint-plugin-n@^15.7.0: - version "15.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz#e29221d8f5174f84d18f2eb94765f2eeea033b90" - integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== - dependencies: - builtins "^5.0.1" - eslint-plugin-es "^4.1.0" - eslint-utils "^3.0.0" - ignore "^5.1.1" - is-core-module "^2.11.0" - minimatch "^3.1.2" - resolve "^1.22.1" - semver "^7.3.8" - -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-plugin-promise@^6.1.1: - version "6.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" - integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== - -eslint-plugin-security@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-security/-/eslint-plugin-security-1.7.1.tgz#0e9c4a471f6e4d3ca16413c7a4a51f3966ba16e4" - integrity sha512-sMStceig8AFglhhT2LqlU5r+/fn9OwsA72O5bBuQVTssPCdQAOQzL+oMn/ZcpeUY6KcNfLJArgcrsSULNjYYdQ== - dependencies: - safe-regex "^2.1.1" - -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== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.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== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.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== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@^8.37.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - 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" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - -esquery@^1.4.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -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" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - -fast-glob@^3.2.9, fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - 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: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - -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 "^3.0.4" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -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: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" - -flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -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-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - -get-tsconfig@^4.7.5: - version "4.8.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.0.tgz#125dc13a316f61650a12b20c97c11b8fd996fedd" - integrity sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw== - dependencies: - resolve-pkg-maps "^1.0.0" - -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-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@^10.3.10: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" - integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== - dependencies: - define-properties "^1.2.1" - gopd "^1.0.1" - -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: - 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" - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - -iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -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== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-bun-module@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.1.0.tgz#a66b9830869437f6cdad440ba49ab6e4dc837269" - integrity sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA== - dependencies: - semver "^7.6.3" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" - integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== - dependencies: - hasown "^2.0.2" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.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-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -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== - -is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -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 "^2.0.1" - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -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: - p-locate "^5.0.0" - -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== - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -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.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -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== - -micromatch@^4.0.4: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -minimatch@^3.0.5, minimatch@^3.1.1, 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" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -mkdirp@^2.1.3: - version "2.1.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -mysql2@^2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" - integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== - dependencies: - denque "^2.0.1" - generate-function "^2.3.1" - iconv-lite "^0.6.3" - long "^4.0.0" - lru-cache "^6.0.0" - named-placeholders "^1.1.2" - seq-queue "^0.0.5" - sqlstring "^2.3.2" - -mysql@^2.18.1: - version "2.18.1" - resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" - integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig== - dependencies: - bignumber.js "9.0.0" - readable-stream "2.3.7" - safe-buffer "5.1.2" - sqlstring "2.3.1" - -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -named-placeholders@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" - integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== - dependencies: - lru-cache "^7.14.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" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.fromentries@^2.0.7: - version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - -object.groupby@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" - integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - -object.values@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -optionator@^0.9.3: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.5" - -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-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -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 sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -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-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -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== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -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== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.8.7: - 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== - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -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== - -readable-stream@2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -reflect-metadata@^0.1.13: - version "0.1.14" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859" - integrity sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A== - -reflect-metadata@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" - integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== - -regexp-tree@~0.1.1: - version "0.1.27" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" - integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== - -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -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== - -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== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - -resolve@^1.22.1, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -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@^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-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: - queue-microtask "^1.2.2" - -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - -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" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -safe-regex@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" - integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== - dependencies: - regexp-tree "~0.1.1" - -"safer-buffer@>= 2.1.2 < 3.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.0.0, semver@^7.3.7, semver@^7.3.8, semver@^7.6.3: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -seq-queue@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -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 "^3.0.0" - -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== - -side-channel@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -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" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" - integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ== - -sqlstring@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" - integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== - -"string-width-cjs@npm:string-width@^4.2.0": - 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== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, 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== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -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== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -ts-mysql-migrate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ts-mysql-migrate/-/ts-mysql-migrate-1.0.2.tgz#736d37c3aa3fef92f226b869098e939950d0e18c" - integrity sha512-zDW6iQsfPCJfQ3JMhfUGjhy8aK+VNTvPrXmJH66PB2EGEvyn4m7x2nBdhDNhKuwYU9LMxW1p+l39Ei+btXNpxA== - dependencies: - "@types/mysql" "^2.15.8" - mysql "^2.18.1" - -ts-node@^10.2.1: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tsconfig-paths@^3.15.0: - version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.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== - -tslib@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== - -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.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.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== - -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typeorm@^0.3.16: - version "0.3.20" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab" - integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q== - dependencies: - "@sqltools/formatter" "^1.2.5" - app-root-path "^3.1.0" - buffer "^6.0.3" - chalk "^4.1.2" - cli-highlight "^2.1.11" - dayjs "^1.11.9" - debug "^4.3.4" - dotenv "^16.0.3" - glob "^10.3.10" - mkdirp "^2.1.3" - reflect-metadata "^0.2.1" - sha.js "^2.4.11" - tslib "^2.5.0" - uuid "^9.0.0" - yargs "^17.6.2" - -typescript@^4.3.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -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== - -uuid@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - -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" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -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" - -word-wrap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -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@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -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@^16.0.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^17.6.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - 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" - 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== diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml index 888bb551e..e69c736fe 100644 --- a/docker-compose.apple-m1.override.yml +++ b/docker-compose.apple-m1.override.yml @@ -33,12 +33,6 @@ services: ######################################################## database: platform: linux/amd64 - - ######################################################## - # DLT-DATABASE ############################################# - ######################################################## - dlt-database: - platform: linux/amd64 ######################################################### ## NGINX ################################################ diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 4807a6bbf..eb7b54269 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -148,28 +148,6 @@ services: # bind the local folder to the docker to allow live reload - ./database:/app - ######################################################## - # DLT-DATABASE ############################################## - ######################################################## - dlt-database: - # we always run on production here since else the service lingers - # feel free to change this behaviour if it seems useful - # Due to problems with the volume caching the built files - # we changed this to test build. This keeps the service running. - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/dlt-database:local-test_up - build: - target: test_up - environment: - - NODE_ENV="development" - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - dlt-database_node_modules:/app/node_modules - - dlt-database_build:/app/build - # bind the local folder to the docker to allow live reload - - ./dlt-database:/app - ######################################################### ## MARIADB ############################################## ######################################################### diff --git a/docker-compose.reset.yml b/docker-compose.reset.yml index 13708bdef..afc9b5a80 100644 --- a/docker-compose.reset.yml +++ b/docker-compose.reset.yml @@ -32,33 +32,6 @@ services: # Application only envs #env_file: # - ./frontend/.env - - ######################################################## - # DLT-DATABASE ############################################# - ######################################################## - dlt-database: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/dlt-database:local-production_reset - build: - context: ./dlt-database - target: production_reset - depends_on: - - mariadb - networks: - - internal-net - - external-net # this is required to fetch the packages - environment: - # Envs used in Dockerfile - # - DOCKER_WORKDIR="/app" - - BUILD_DATE - - BUILD_VERSION - - BUILD_COMMIT - - NODE_ENV="production" - - DB_HOST=mariadb - # Application only envs - #env_file: - # - ./frontend/.env - networks: external-net: diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 6b6b2c04f..8e45055a4 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -76,18 +76,6 @@ services: - NODE_ENV="test" # restart: always # this is very dangerous, but worth a test for the delayed mariadb startup at first run - ######################################################## - # DLT-DATABASE ############################################# - ######################################################## - dlt-database: - image: gradido/dlt-database:test_up - build: - context: ./dlt-database - target: test_up - environment: - - NODE_ENV="test" - # restart: always # this is very dangerous, but worth a test for the delayed mariadb startup at first run - ######################################################### ## MARIADB ############################################## ######################################################### diff --git a/docker-compose.yml b/docker-compose.yml index 76243a98a..9d84aea34 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -239,32 +239,6 @@ services: #env_file: # - ./frontend/.env - ######################################################## - # DLT-DATABASE ############################################# - ######################################################## - dlt-database: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/dlt-database:local-production_up - build: - context: ./dlt-database - target: production_up - depends_on: - - mariadb - networks: - - internal-net - - external-net # this is required to fetch the packages - environment: - # Envs used in Dockerfile - # - DOCKER_WORKDIR="/app" - - BUILD_DATE - - BUILD_VERSION - - BUILD_COMMIT - - NODE_ENV="production" - - DB_HOST=mariadb - # Application only envs - #env_file: - # - ./frontend/.env - ######################################################### ## NGINX ################################################ ######################################################### From e1cc58381eeee4cc4f5b492471605ce1387d5434 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sun, 22 Sep 2024 17:29:12 +0200 Subject: [PATCH 011/226] fix db version, remove olddated tests --- backend/src/config/index.ts | 2 +- dht-node/src/config/index.ts | 2 +- dlt-connector/.env.dist | 9 - dlt-connector/.env.template | 9 - dlt-connector/jest.config.js | 11 - dlt-connector/package.json | 2 +- dlt-connector/src/config/index.ts | 14 +- dlt-connector/src/graphql/model/Community.ts | 36 -- .../resolver/CommunityResolver.test.ts | 87 --- .../resolver/TransactionsResolver.test.ts | 218 ------- dlt-connector/src/index.ts | 7 +- dlt-connector/src/server/createServer.ts | 3 - dlt-connector/src/typeorm/DataSource.ts | 89 --- dlt-connector/test/TestDB.ts | 77 --- dlt-connector/test/seeding/Community.seed.ts | 28 - dlt-connector/test/seeding/UserSet.seed.ts | 55 -- dlt-connector/tsconfig.json | 6 - dlt-connector/yarn.lock | 550 +----------------- federation/src/config/index.ts | 2 +- 19 files changed, 19 insertions(+), 1188 deletions(-) delete mode 100644 dlt-connector/src/graphql/model/Community.ts delete mode 100644 dlt-connector/src/graphql/resolver/CommunityResolver.test.ts delete mode 100644 dlt-connector/src/graphql/resolver/TransactionsResolver.test.ts delete mode 100644 dlt-connector/src/typeorm/DataSource.ts delete mode 100644 dlt-connector/test/TestDB.ts delete mode 100644 dlt-connector/test/seeding/Community.seed.ts delete mode 100644 dlt-connector/test/seeding/UserSet.seed.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index d66f729db..7ded1b8f4 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0086-add_community_location', + DB_VERSION: '0087-add_dlt_users_table', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 8bf59c465..f2dc456b4 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -4,7 +4,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0086-add_community_location', + DB_VERSION: '0087-add_dlt_users_table', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 8ad78348d..ba8fe5557 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -9,15 +9,6 @@ IOTA_API_URL=https://chrysalis-nodes.iota.org IOTA_COMMUNITY_ALIAS=GRADIDO: TestHelloWelt2 IOTA_HOME_COMMUNITY_SEED=aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_dlt -DB_DATABASE_TEST=gradido_dlt_test -TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log - # DLT-Connector DLT_CONNECTOR_PORT=6010 diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 15c2ae5a9..ac27481bb 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -7,15 +7,6 @@ IOTA_API_URL=$IOTA_API_URL IOTA_COMMUNITY_ALIAS=$IOTA_COMMUNITY_ALIAS IOTA_HOME_COMMUNITY_SEED=$IOTA_HOME_COMMUNITY_SEED -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_dlt -DB_DATABASE_TEST=$DB_DATABASE_TEST -TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log - # DLT-Connector DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT diff --git a/dlt-connector/jest.config.js b/dlt-connector/jest.config.js index 9b5a01350..652408b23 100644 --- a/dlt-connector/jest.config.js +++ b/dlt-connector/jest.config.js @@ -22,18 +22,7 @@ module.exports = { '@input/(.*)': '/src/graphql/input/$1', '@proto/(.*)': '/src/proto/$1', '@test/(.*)': '/test/$1', - '@typeorm/(.*)': '/src/typeorm/$1', '@client/(.*)': '/src/client/$1', - '@entity/(.*)': - // eslint-disable-next-line n/no-process-env - process.env.NODE_ENV === 'development' - ? '/../dlt-database/entity/$1' - : '/../dlt-database/build/entity/$1', - '@dbTools/(.*)': - // eslint-disable-next-line n/no-process-env - process.env.NODE_ENV === 'development' - ? '/../dlt-database/src/$1' - : '/../dlt-database/build/src/$1', '@validator/(.*)': '/src/graphql/validator/$1', }, } diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 6031dd3b0..db7192cc1 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -13,7 +13,7 @@ "start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js", "dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts", "lint": "eslint --max-warnings=0 --ext .js,.ts .", - "test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles" + "test": "cross-env TZ=UTC NODE_ENV=development jest --forceExit --detectOpenHandles" }, "dependencies": { "@apollo/server": "^4.7.5", diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index ff50eb3fe..806d3fd50 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -4,7 +4,6 @@ dotenv.config() const constants = { LOG4JS_CONFIG: 'log4js-config.json', - DB_VERSION: '0005-refactor_with_gradido_blockchain_lib', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', CONFIG_VERSION: { @@ -19,20 +18,10 @@ const server = { JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', } -const database = { - DB_HOST: process.env.DB_HOST ?? 'localhost', - DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER ?? 'root', - DB_PASSWORD: process.env.DB_PASSWORD ?? '', - DB_DATABASE: process.env.DB_DATABASE ?? 'gradido_dlt', - DB_DATABASE_TEST: process.env.DB_DATABASE_TEST ?? 'gradido_dlt_test', - TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH ?? 'typeorm.backend.log', -} - const iota = { IOTA_API_URL: process.env.IOTA_API_URL ?? 'https://chrysalis-nodes.iota.org', IOTA_COMMUNITY_ALIAS: process.env.IOTA_COMMUNITY_ALIAS ?? 'GRADIDO: TestHelloWelt2', - IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED?.substring(0, 32) ?? null, + IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED ?? null, } const dltConnector = { @@ -69,7 +58,6 @@ if ( export const CONFIG = { ...constants, ...server, - ...database, ...iota, ...dltConnector, ...nodeServer, diff --git a/dlt-connector/src/graphql/model/Community.ts b/dlt-connector/src/graphql/model/Community.ts deleted file mode 100644 index 7a69288dc..000000000 --- a/dlt-connector/src/graphql/model/Community.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Community as CommunityEntity } from '@entity/Community' -import { ObjectType, Field, Int } from 'type-graphql' - -@ObjectType() -export class Community { - constructor(entity: CommunityEntity) { - this.id = entity.id - this.iotaTopic = entity.iotaTopic - if (entity.rootPubkey) { - this.rootPublicKeyHex = entity.rootPubkey?.toString('hex') - } - this.foreign = entity.foreign - this.createdAt = entity.createdAt.toString() - if (entity.confirmedAt) { - this.confirmedAt = entity.confirmedAt.toString() - } - } - - @Field(() => Int) - id: number - - @Field(() => String) - iotaTopic: string - - @Field(() => String) - rootPublicKeyHex?: string - - @Field(() => Boolean) - foreign: boolean - - @Field(() => String) - createdAt: string - - @Field(() => String) - confirmedAt?: string -} diff --git a/dlt-connector/src/graphql/resolver/CommunityResolver.test.ts b/dlt-connector/src/graphql/resolver/CommunityResolver.test.ts deleted file mode 100644 index 0fa61cc48..000000000 --- a/dlt-connector/src/graphql/resolver/CommunityResolver.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import 'reflect-metadata' -import assert from 'assert' - -import { ApolloServer } from '@apollo/server' - -// must be imported before createApolloTestServer so that TestDB was created before createApolloTestServer imports repositories -// eslint-disable-next-line import/order -import { TestDB } from '@test/TestDB' -import { TransactionResult } from '@model/TransactionResult' -import { createApolloTestServer } from '@test/ApolloServerMock' - -import { CONFIG } from '@/config' - -CONFIG.IOTA_HOME_COMMUNITY_SEED = 'aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899' - -const con = TestDB.instance - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -let apolloTestServer: ApolloServer - -describe('graphql/resolver/CommunityResolver', () => { - beforeAll(async () => { - await con.setupTestDB() - apolloTestServer = await createApolloTestServer() - }) - afterAll(async () => { - await con.teardownTestDB() - }) - - describe('tests with db', () => { - it('test add foreign community', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: CommunityDraft!) { addCommunity(data: $input) {succeed, error {message}} }', - variables: { - input: { - uuid: '3d813cbb-37fb-42ba-91df-831e1593ac29', - foreign: true, - createdAt: '2012-04-17T17:12:00.0012Z', - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult.errors).toBeUndefined() - const transactionResult = response.body.singleResult.data?.addCommunity as TransactionResult - expect(transactionResult.succeed).toEqual(true) - }) - - it('test add home community', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: CommunityDraft!) { addCommunity(data: $input) {succeed, error {message}} }', - variables: { - input: { - uuid: '3d823cad-37fb-41cd-91df-152e1593ac29', - foreign: false, - createdAt: '2012-05-12T13:12:00.2917Z', - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult.errors).toBeUndefined() - const transactionResult = response.body.singleResult.data?.addCommunity as TransactionResult - expect(transactionResult.succeed).toEqual(true) - }) - - it('test add existing community', async () => { - const response = await apolloTestServer.executeOperation({ - query: 'mutation ($input: CommunityDraft!) { addCommunity(data: $input) {succeed} }', - variables: { - input: { - uuid: '3d823cad-37fb-41cd-91df-152e1593ac29', - foreign: false, - createdAt: '2012-05-12T13:12:00.1271Z', - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult.errors).toBeUndefined() - const transactionResult = response.body.singleResult.data?.addCommunity as TransactionResult - expect(transactionResult.succeed).toEqual(false) - }) - }) -}) diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.test.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.test.ts deleted file mode 100644 index 6eb443e21..000000000 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.test.ts +++ /dev/null @@ -1,218 +0,0 @@ -import 'reflect-metadata' -import assert from 'assert' - -import { ApolloServer } from '@apollo/server' - -// must be imported before createApolloTestServer so that TestDB was created before createApolloTestServer imports repositories -// eslint-disable-next-line import/order -import { TestDB } from '@test/TestDB' -import { AccountType } from '@enum/AccountType' -import { TransactionResult } from '@model/TransactionResult' -import { createApolloTestServer } from '@test/ApolloServerMock' - -import { CONFIG } from '@/config' -import { AccountFactory } from '@/data/Account.factory' -import { KeyPair } from '@/data/KeyPair' -import { Mnemonic } from '@/data/Mnemonic' -import { UserFactory } from '@/data/User.factory' -import { UserLogic } from '@/data/User.logic' -import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' -import { getEnumValue } from '@/utils/typeConverter' - -import { InputTransactionType } from '../enum/InputTransactionType' -import { CommunityDraft } from '../input/CommunityDraft' -import { UserAccountDraft } from '../input/UserAccountDraft' -import { UserIdentifier } from '../input/UserIdentifier' - -let apolloTestServer: ApolloServer - -jest.mock('@/client/IotaClient', () => { - return { - sendMessage: jest.fn().mockReturnValue({ - messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', - }), - } -}) - -jest.mock('@typeorm/DataSource', () => ({ - getDataSource: jest.fn(() => TestDB.instance.dbConnect), -})) - -CONFIG.IOTA_HOME_COMMUNITY_SEED = 'aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899' -const communityUUID = '3d813cbb-37fb-42ba-91df-831e1593ac29' -const communityKeyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED)) - -const createUserStoreAccount = async (uuid: string): Promise => { - const userAccountDraft = new UserAccountDraft() - userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN - userAccountDraft.createdAt = new Date().toString() - userAccountDraft.user = new UserIdentifier() - userAccountDraft.user.uuid = uuid - userAccountDraft.user.communityUuid = communityUUID - const user = UserFactory.create(userAccountDraft, communityKeyPair) - const userLogic = new UserLogic(user) - const account = AccountFactory.createAccountFromUserAccountDraft( - userAccountDraft, - userLogic.calculateKeyPair(communityKeyPair), - ) - account.user = user - // user is set to cascade: ['insert'] will be saved together with account - await account.save() - return userAccountDraft.user -} - -describe('Transaction Resolver Test', () => { - let user: UserIdentifier - let linkedUser: UserIdentifier - beforeAll(async () => { - await TestDB.instance.setupTestDB() - apolloTestServer = await createApolloTestServer() - - const communityDraft = new CommunityDraft() - communityDraft.uuid = communityUUID - communityDraft.foreign = false - communityDraft.createdAt = new Date().toString() - const addCommunityContext = new AddCommunityContext(communityDraft) - await addCommunityContext.run() - user = await createUserStoreAccount('0ec72b74-48c2-446f-91ce-31ad7d9f4d65') - linkedUser = await createUserStoreAccount('ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe') - }) - - afterAll(async () => { - await TestDB.instance.teardownTestDB() - }) - - it('test mocked sendTransaction', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {succeed, recipe { id, topic }} }', - variables: { - input: { - user, - linkedUser, - type: getEnumValue(InputTransactionType, InputTransactionType.SEND), - amount: '10', - createdAt: '2012-04-17T17:12:00Z', - backendTransactionId: 1, - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult.errors).toBeUndefined() - const transactionResult = response.body.singleResult.data?.sendTransaction as TransactionResult - expect(transactionResult.recipe).toBeDefined() - expect(transactionResult.succeed).toBe(true) - }) - - it('test mocked sendTransaction invalid transactionType ', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, succeed} }', - variables: { - input: { - user, - linkedUser, - type: 'INVALID', - amount: '10', - createdAt: '2012-04-17T17:12:00Z', - backendTransactionId: 1, - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult).toMatchObject({ - errors: [ - { - message: - 'Variable "$input" got invalid value "INVALID" at "input.type"; Value "INVALID" does not exist in "InputTransactionType" enum.', - }, - ], - }) - }) - - it('test mocked sendTransaction invalid amount ', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, succeed} }', - variables: { - input: { - user, - linkedUser, - type: getEnumValue(InputTransactionType, InputTransactionType.SEND), - amount: 'no number', - createdAt: '2012-04-17T17:12:00Z', - backendTransactionId: 1, - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult).toMatchObject({ - errors: [ - { - message: - 'Variable "$input" got invalid value "no number" at "input.amount"; Expected type "Decimal". [DecimalError] Invalid argument: no number', - }, - ], - }) - }) - - it('test mocked sendTransaction invalid created date ', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, succeed} }', - variables: { - input: { - user, - linkedUser, - type: getEnumValue(InputTransactionType, InputTransactionType.SEND), - amount: '10', - createdAt: 'not valid', - backendTransactionId: 1, - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult).toMatchObject({ - errors: [ - { - message: 'Argument Validation Error', - extensions: { - code: 'BAD_USER_INPUT', - validationErrors: [ - { - value: 'not valid', - property: 'createdAt', - constraints: { - isValidDateString: 'createdAt must be a valid date string', - }, - }, - ], - }, - }, - ], - }) - }) - it('test mocked sendTransaction missing creationDate for contribution', async () => { - const response = await apolloTestServer.executeOperation({ - query: - 'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, succeed} }', - variables: { - input: { - user, - linkedUser, - type: getEnumValue(InputTransactionType, InputTransactionType.CREATION), - amount: '10', - createdAt: '2012-04-17T17:12:00Z', - backendTransactionId: 1, - }, - }, - }) - assert(response.body.kind === 'single') - expect(response.body.singleResult.data?.sendTransaction).toMatchObject({ - error: { - type: 'MISSING_PARAMETER', - message: 'missing targetDate for contribution', - }, - }) - }) -}) diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 2dd21b66b..c025296fd 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -6,14 +6,14 @@ import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { CONFIG } from '@/config' import { BackendClient } from './client/BackendClient' +import { getTransaction } from './client/GradidoNode' import { CommunityDraft } from './graphql/input/CommunityDraft' +import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' import { logger } from './logging/logger' import { KeyPairCacheManager } from './manager/KeyPairCacheManager' import createServer from './server/createServer' import { LogError } from './server/LogError' -import { getTransaction } from './client/GradidoNode' import { uuid4ToHash } from './utils/typeConverter' -import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' async function waitForServer( backend: BackendClient, @@ -46,9 +46,10 @@ async function main() { if (seed.size() < 32) { throw new Error('seed need to be greater than 32 Bytes') } - } catch (_) { + } catch (error) { throw new LogError( 'IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long', + error, ) } } diff --git a/dlt-connector/src/server/createServer.ts b/dlt-connector/src/server/createServer.ts index 25e0a12e2..9cc29124c 100755 --- a/dlt-connector/src/server/createServer.ts +++ b/dlt-connector/src/server/createServer.ts @@ -12,7 +12,6 @@ import { Logger } from 'log4js' import { schema } from '@/graphql/schema' import { logger as dltLogger } from '@/logging/logger' -import { Connection } from '@/typeorm/DataSource' type ServerDef = { apollo: ApolloServer; app: Express } @@ -29,8 +28,6 @@ const createServer = async ( logger.addContext('user', 'unknown') logger.debug('createServer...') - // connect to db and test db version - await Connection.getInstance().init() // Express Server const app = express() diff --git a/dlt-connector/src/typeorm/DataSource.ts b/dlt-connector/src/typeorm/DataSource.ts deleted file mode 100644 index a86a061f3..000000000 --- a/dlt-connector/src/typeorm/DataSource.ts +++ /dev/null @@ -1,89 +0,0 @@ -// TODO This is super weird - since the entities are defined in another project they have their own globals. -// We cannot use our connection here, but must use the external typeorm installation -import { DataSource as DBDataSource, FileLogger } from '@dbTools/typeorm' -import { entities } from '@entity/index' -import { Migration } from '@entity/Migration' - -import { CONFIG } from '@/config' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' - -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class Connection { - // eslint-disable-next-line no-use-before-define - private static instance: Connection - private connection: DBDataSource - - /** - * The Singleton's constructor should always be private to prevent direct - * construction calls with the `new` operator. - */ - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor() { - this.connection = new DBDataSource({ - type: 'mysql', - host: CONFIG.DB_HOST, - port: CONFIG.DB_PORT, - username: CONFIG.DB_USER, - password: CONFIG.DB_PASSWORD, - database: CONFIG.DB_DATABASE, - entities, - synchronize: false, - logging: true, - logger: new FileLogger('all', { - logPath: CONFIG.TYPEORM_LOGGING_RELATIVE_PATH, - }), - extra: { - charset: 'utf8mb4_unicode_ci', - }, - }) - } - - /** - * The static method that controls the access to the singleton instance. - * - * This implementation let you subclass the Singleton class while keeping - * just one instance of each subclass around. - */ - public static getInstance(): Connection { - if (!Connection.instance) { - Connection.instance = new Connection() - } - return Connection.instance - } - - public getDataSource(): DBDataSource { - return this.connection - } - - public async init(): Promise { - await this.connection.initialize() - try { - Connection.getInstance() - } catch (error) { - // try and catch for logging - logger.fatal(`Couldn't open connection to database!`) - throw error - } - - // check for correct database version - await this.checkDBVersion(CONFIG.DB_VERSION) - } - - async checkDBVersion(DB_VERSION: string): Promise { - const dbVersion = await Migration.find({ order: { version: 'DESC' }, take: 1 }) - if (!dbVersion || dbVersion.length < 1) { - throw new LogError('found no db version in migrations, could dlt-database run successfully?') - } - // return dbVersion ? dbVersion.fileName : null - if (!dbVersion[0].fileName.includes(DB_VERSION)) { - throw new LogError( - `Wrong database version detected - the backend requires '${DB_VERSION}' but found '${ - dbVersion[0].fileName ?? 'None' - }`, - ) - } - } -} - -export const getDataSource = () => Connection.getInstance().getDataSource() diff --git a/dlt-connector/test/TestDB.ts b/dlt-connector/test/TestDB.ts deleted file mode 100644 index 63ce78500..000000000 --- a/dlt-connector/test/TestDB.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { DataSource, FileLogger } from '@dbTools/typeorm' -import { entities } from '@entity/index' -import { createDatabase } from 'typeorm-extension' - -import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' - -// TODO: maybe use in memory db like here: https://dkzeb.medium.com/unit-testing-in-ts-jest-with-typeorm-entities-ad5de5f95438 -export class TestDB { - // eslint-disable-next-line no-use-before-define - private static _instance: TestDB - - private constructor() { - if (!CONFIG.DB_DATABASE_TEST) { - throw new LogError('no test db in config') - } - if (CONFIG.DB_DATABASE === CONFIG.DB_DATABASE_TEST) { - throw new LogError( - 'main db is the same as test db, not good because test db will be cleared after each test run', - ) - } - this.dbConnect = new DataSource({ - type: 'mysql', - host: CONFIG.DB_HOST, - port: CONFIG.DB_PORT, - username: CONFIG.DB_USER, - password: CONFIG.DB_PASSWORD, - database: CONFIG.DB_DATABASE_TEST, - entities, - synchronize: true, - dropSchema: true, - logging: true, - logger: new FileLogger('all', { - logPath: CONFIG.TYPEORM_LOGGING_RELATIVE_PATH, - }), - extra: { - charset: 'utf8mb4_unicode_ci', - }, - }) - } - - public static get instance(): TestDB { - if (!this._instance) this._instance = new TestDB() - return this._instance - } - - public dbConnect!: DataSource - - async setupTestDB() { - // eslint-disable-next-line no-console - try { - if (!CONFIG.DB_DATABASE_TEST) { - throw new LogError('no test db in config') - } - await createDatabase({ - ifNotExist: true, - options: { - type: 'mysql', - charset: 'utf8mb4_unicode_ci', - host: CONFIG.DB_HOST, - port: CONFIG.DB_PORT, - username: CONFIG.DB_USER, - password: CONFIG.DB_PASSWORD, - database: CONFIG.DB_DATABASE_TEST, - }, - }) - await this.dbConnect.initialize() - } catch (error) { - // eslint-disable-next-line no-console - console.log(error) - } - } - - async teardownTestDB() { - await this.dbConnect.destroy() - } -} diff --git a/dlt-connector/test/seeding/Community.seed.ts b/dlt-connector/test/seeding/Community.seed.ts deleted file mode 100644 index 8dee407f3..000000000 --- a/dlt-connector/test/seeding/Community.seed.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Community } from '@entity/Community' - -import { KeyPair } from '@/data/KeyPair' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context' -import { uuid4ToHash } from '@/utils/typeConverter' - -export const communitySeed = async ( - uuid: string, - foreign: boolean, - keyPair: KeyPair | undefined = undefined, -): Promise => { - const homeCommunityDraft = new CommunityDraft() - homeCommunityDraft.uuid = uuid - homeCommunityDraft.foreign = foreign - homeCommunityDraft.createdAt = new Date().toISOString() - const iotaTopic = uuid4ToHash(uuid) - const addCommunityContext = new AddCommunityContext(homeCommunityDraft, iotaTopic) - await addCommunityContext.run() - - const community = await Community.findOneOrFail({ where: { iotaTopic } }) - if (foreign && keyPair) { - // that isn't entirely correct, normally only the public key from foreign community is known, and will be come form blockchain - keyPair.fillInCommunityKeys(community) - await community.save() - } - return community -} diff --git a/dlt-connector/test/seeding/UserSet.seed.ts b/dlt-connector/test/seeding/UserSet.seed.ts deleted file mode 100644 index 933b386ca..000000000 --- a/dlt-connector/test/seeding/UserSet.seed.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Account } from '@entity/Account' -import { User } from '@entity/User' -import { v4 } from 'uuid' - -import { AccountFactory } from '@/data/Account.factory' -import { KeyPair } from '@/data/KeyPair' -import { UserFactory } from '@/data/User.factory' -import { UserLogic } from '@/data/User.logic' -import { AccountType } from '@/graphql/enum/AccountType' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' - -export type UserSet = { - identifier: UserIdentifier - user: User - account: Account -} - -export const createUserIdentifier = (userUuid: string, communityUuid: string): UserIdentifier => { - const user = new UserIdentifier() - user.uuid = userUuid - user.communityUuid = communityUuid - return user -} - -export const createUserAndAccount = ( - userIdentifier: UserIdentifier, - communityKeyPair: KeyPair, -): Account => { - const accountDraft = new UserAccountDraft() - accountDraft.user = userIdentifier - accountDraft.createdAt = new Date().toISOString() - accountDraft.accountType = AccountType.COMMUNITY_HUMAN - const user = UserFactory.create(accountDraft, communityKeyPair) - const userLogic = new UserLogic(user) - const account = AccountFactory.createAccountFromUserAccountDraft( - accountDraft, - userLogic.calculateKeyPair(communityKeyPair), - ) - account.user = user - return account -} - -export const createUserSet = (communityUuid: string, communityKeyPair: KeyPair): UserSet => { - const identifier = createUserIdentifier(v4(), communityUuid) - const account = createUserAndAccount(identifier, communityKeyPair) - if (!account.user) { - throw Error('user missing') - } - return { - identifier, - account, - user: account.user, - } -} diff --git a/dlt-connector/tsconfig.json b/dlt-connector/tsconfig.json index 32525c013..2ce9731e3 100644 --- a/dlt-connector/tsconfig.json +++ b/dlt-connector/tsconfig.json @@ -53,14 +53,9 @@ "@input/*": ["src/graphql/input/*"], "@model/*": ["src/graphql/model/*"], "@resolver/*": ["src/graphql/resolver/*"], - "@scalar/*": ["src/graphql/scalar/*"], "@test/*": ["test/*"], "@proto/*" : ["src/proto/*"], "@validator/*" : ["src/graphql/validator/*"], - "@typeorm/*" : ["src/typeorm/*"], - /* external */ - "@dbTools/*": ["../dlt-database/src/*", "../../dlt-database/build/src/*"], - "@entity/*": ["../dlt-database/entity/*", "../../dlt-database/build/entity/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["node_modules/@types", "@types"], /* List of folders to include type definitions from. */ @@ -86,7 +81,6 @@ }, "references": [ { - "path": "../dlt-database/tsconfig.json", // add 'prepend' if you want to include the referenced project in your output file // "prepend": true } diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index 64ebb063a..c4f244816 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -481,11 +481,6 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@faker-js/faker@^8.4.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451" - integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg== - "@graphql-tools/merge@^8.4.1": version "8.4.2" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.4.2.tgz#95778bbe26b635e8d2f60ce9856b388f11fe8288" @@ -600,18 +595,6 @@ neon-cli "^0.8" prebuild-install "^6.1.2" -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -863,11 +846,6 @@ resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -945,11 +923,6 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@sqltools/formatter@^1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12" - integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -1109,13 +1082,6 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/mysql@^2.15.8": - version "2.15.26" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" - integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== - dependencies: - "@types/node" "*" - "@types/node-fetch@^2.6.1": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" @@ -1394,11 +1360,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-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1418,16 +1379,6 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -1436,11 +1387,6 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -app-root-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" - integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -1679,11 +1625,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bignumber.js@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" - integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== - binary-extensions@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" @@ -1747,13 +1688,6 @@ 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.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -1803,14 +1737,6 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -1873,7 +1799,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +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== @@ -1942,18 +1868,6 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-highlight@^2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" @@ -2084,11 +1998,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -consola@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" - integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== - console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" @@ -2177,7 +2086,7 @@ cross-inspect@1.0.1: dependencies: tslib "^2.4.0" -cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2186,11 +2095,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" - integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== - cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" @@ -2249,11 +2153,6 @@ date-format@^4.0.14: resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== -dayjs@^1.11.9: - version "1.11.13" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" - integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== - debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2275,11 +2174,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -decimal.js-light@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" - integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== - decimal.js@^10.2.1: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" @@ -2340,11 +2234,6 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -denque@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" - integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== - depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -2355,11 +2244,6 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== -destr@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" - integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== - destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -2397,20 +2281,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -"dlt-database@file:../dlt-database": - version "1.23.2" - dependencies: - "@types/uuid" "^8.3.4" - cross-env "^7.0.3" - crypto "^1.0.1" - decimal.js-light "^2.5.1" - dotenv "^10.0.0" - mysql2 "^2.3.0" - reflect-metadata "^0.1.13" - ts-mysql-migrate "^1.0.2" - typeorm "^0.3.16" - uuid "^8.3.2" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2432,38 +2302,16 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -dotenv@10.0.0, dotenv@^10.0.0: +dotenv@10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -dotenv@^16.0.3: - version "16.4.5" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" - integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== - dset@^3.1.2: version "3.1.4" resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ebec@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ebec/-/ebec-1.1.1.tgz#683a0dc82a77e86349e05b24c43d7233a6d0f840" - integrity sha512-JZ1vcvPQtR+8LGbZmbjG21IxLQq/v47iheJqn2F6yB2CgnGfn8ZVg3myHrf3buIZS8UCwQK0jOSIb3oHX7aH8g== - dependencies: - smob "^1.4.0" - -ebec@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/ebec/-/ebec-2.3.0.tgz#9b5b423f1196a0cd414e041111f2b1d146308bd5" - integrity sha512-bt+0tSL7223VU3PSVi0vtNLZ8pO1AfWolcPPMk2a/a5H+o/ZU9ky0n3A0zhrR4qzJTN61uPsGIO4ShhOukdzxA== - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2484,11 +2332,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2514,13 +2357,6 @@ enhanced-resolve@^5.15.0: graceful-fs "^4.2.4" tapable "^2.2.0" -envix@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/envix/-/envix-1.5.0.tgz#bbb7ceba6f098a272ef2044e606789844d08c1db" - integrity sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w== - dependencies: - std-env "^3.7.0" - error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3179,11 +3015,6 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - flatted@^3.2.7, flatted@^3.2.9: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" @@ -3201,14 +3032,6 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - form-data@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" @@ -3325,13 +3148,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -3405,18 +3221,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.3.10: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -3583,11 +3387,6 @@ helmet@^7.1.0: resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -3662,14 +3461,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -3890,11 +3682,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== - is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -4005,15 +3792,6 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - jest-changed-files@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" @@ -4419,11 +4197,6 @@ jest@^27.2.4: import-local "^3.0.2" jest-cli "^27.5.1" -jiti@^1.21.6: - version "1.21.6" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" - integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== - jose@^5.2.2: version "5.9.2" resolved "https://registry.yarnpkg.com/jose/-/jose-5.9.2.tgz#22a22da06edb8fb9e583aa24bafc1e8457b4db92" @@ -4592,18 +4365,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -locter@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/locter/-/locter-2.1.1.tgz#31be1c81db8268162c4c3e4d2700df3f7ed235cc" - integrity sha512-trTg69NVZkfo/70BW7cXAZkFEFDWlQwPcNUO1aDZs/HhOzt7jBPSWldGqK/RXQDmb2tWCpPdRmrHMSXPRm3B2w== - dependencies: - destr "^2.0.3" - ebec "^2.3.0" - fast-glob "^3.3.2" - flat "^5.0.2" - jiti "^1.21.6" - yaml "^2.5.0" - lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -4660,18 +4421,6 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4679,13 +4428,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -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.10.1, lru-cache@^7.14.1: version "7.18.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" @@ -4794,13 +4536,6 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -4818,11 +4553,6 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -4841,11 +4571,6 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^2.1.3: - version "2.1.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4866,46 +4591,6 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mysql2@^2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" - integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== - dependencies: - denque "^2.0.1" - generate-function "^2.3.1" - iconv-lite "^0.6.3" - long "^4.0.0" - lru-cache "^6.0.0" - named-placeholders "^1.1.2" - seq-queue "^0.0.5" - sqlstring "^2.3.2" - -mysql@^2.18.1: - version "2.18.1" - resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" - integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig== - dependencies: - bignumber.js "9.0.0" - readable-stream "2.3.7" - safe-buffer "5.1.2" - sqlstring "2.3.1" - -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -named-placeholders@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351" - integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w== - dependencies: - lru-cache "^7.14.1" - nan@^2.20.0: version "2.20.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" @@ -4956,14 +4641,6 @@ neon-cli@^0.8: validate-npm-package-license "^3.0.4" validate-npm-package-name "^3.0.0" -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - node-abi@^2.21.0: version "2.30.1" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" @@ -5096,7 +4773,7 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -5227,11 +4904,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -package-json-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5249,36 +4921,16 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@6.0.1, parse5@^6.0.1: +parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -5299,14 +4951,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-to-regexp@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" @@ -5484,14 +5128,6 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -rapiq@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/rapiq/-/rapiq-0.9.0.tgz#0f427b1a459064a488ae86d2fb91f14524369240" - integrity sha512-k4oT4RarFBrlLMJ49xUTeQpa/us0uU4I70D/UEnK3FWQ4GENzei01rEQAmvPKAIzACo4NMW+YcYJ7EVfSa7EFg== - dependencies: - ebec "^1.1.0" - smob "^1.4.0" - raw-body@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" @@ -5527,19 +5163,6 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -readable-stream@2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readable-stream@^2.0.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -5579,11 +5202,6 @@ reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859" integrity sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A== -reflect-metadata@^0.2.1, reflect-metadata@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" - integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== - regexp-tree@~0.1.1: version "0.1.27" resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" @@ -5735,7 +5353,7 @@ safe-regex@^2.1.1: dependencies: regexp-tree "~0.1.1" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5805,11 +5423,6 @@ send@0.19.0: range-parser "~1.2.1" statuses "2.0.1" -seq-queue@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q== - serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -5902,11 +5515,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -5938,11 +5546,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -smob@^1.4.0, smob@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" - integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== - source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -5992,16 +5595,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sqlstring@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" - integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ== - -sqlstring@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" - integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -6019,11 +5612,6 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -std-env@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" - integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== - streamroller@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" @@ -6041,15 +5629,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - 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== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -6068,15 +5647,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - string.prototype.trim@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" @@ -6119,13 +5689,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -6140,13 +5703,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -6281,20 +5837,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - throat@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" @@ -6385,14 +5927,6 @@ ts-jest@^27.0.5: semver "7.x" yargs-parser "20.x" -ts-mysql-migrate@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/ts-mysql-migrate/-/ts-mysql-migrate-1.1.2.tgz#6f280f4684cb95440ffa7254b926b494badb8cf3" - integrity sha512-jwhVaMrYBNNhAoZ5XISxzqbnXTHqwazqu/r1UQ6kUaGNPGL43ZFnBiXVj4Gm3pfe3xtCGIaNInehDfdDuigPgw== - dependencies: - "@types/mysql" "^2.15.8" - mysql "^2.18.1" - ts-node@^10.9.1: version "10.9.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" @@ -6441,7 +5975,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.2, tslib@^2.6.2, tslib@^2.6.3: +tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.2, tslib@^2.6.2, tslib@^2.6.3: version "2.7.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== @@ -6553,42 +6087,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeorm-extension@^3.0.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/typeorm-extension/-/typeorm-extension-3.6.1.tgz#e40711951db48ed59e22ccdebcc43d5527acf5e8" - integrity sha512-OyjYrjtu2VgtjU1vJiUcQ5A+auNWgUtSBfZ4rWgMdsBBkzGpOjFKkPrA6B2RdngJfk9KOGNaw34XI0EATw+LqQ== - dependencies: - "@faker-js/faker" "^8.4.1" - consola "^3.2.3" - envix "^1.5.0" - locter "^2.1.0" - pascal-case "^3.1.2" - rapiq "^0.9.0" - reflect-metadata "^0.2.2" - smob "^1.5.0" - yargs "^17.7.2" - -typeorm@^0.3.16, typeorm@^0.3.17: - version "0.3.20" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab" - integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q== - dependencies: - "@sqltools/formatter" "^1.2.5" - app-root-path "^3.1.0" - buffer "^6.0.3" - chalk "^4.1.2" - cli-highlight "^2.1.11" - dayjs "^1.11.9" - debug "^4.3.4" - dotenv "^16.0.3" - glob "^10.3.10" - mkdirp "^2.1.3" - reflect-metadata "^0.2.1" - sha.js "^2.4.11" - tslib "^2.5.0" - uuid "^9.0.0" - yargs "^17.6.2" - typescript@^4.9.4: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -6697,11 +6195,6 @@ 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: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - uuid@^9.0.0, uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -6882,15 +6375,6 @@ wordwrapjs@^4.0.0: reduce-flatten "^2.0.0" typical "^5.2.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -6900,15 +6384,6 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -6954,11 +6429,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" - integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== - yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" @@ -6969,7 +6439,7 @@ yargs-parser@^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@^16.0.0, yargs@^16.2.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -6982,7 +6452,7 @@ yargs@^16.0.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.6.2, yargs@^17.7.2: +yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 0cbebc733..4ada82244 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0086-add_community_location', + DB_VERSION: '0087-add_dlt_users_table', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info From 4dc4451b2f48546fc774229eb20e8c95263ec5f3 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 23 Sep 2024 19:11:00 +0200 Subject: [PATCH 012/226] adjustments --- .../apis/dltConnector/DltConnectorClient.ts | 28 +++++-- backend/src/graphql/resolver/UserResolver.ts | 5 +- .../tasks/sendTransactionsToDltConnector.ts | 84 ++++++++++++------- .../DltTransaction.ts | 36 ++++++++ .../0087-add_dlt_users_table/DltUser.ts | 3 + database/entity/DltTransaction.ts | 2 +- .../migrations/0087-add_dlt_users_table.ts | 27 ++++-- dlt-connector/src/client/GradidoNode.ts | 2 +- .../src/graphql/input/TransactionDraft.ts | 8 +- dlt-connector/src/index.ts | 16 +++- .../sendToIota/CreationTransaction.role.ts | 1 + .../sendToIota/TransferTransaction.role.ts | 1 + .../logging/TransactionDraftLogging.view.ts | 1 - 13 files changed, 161 insertions(+), 53 deletions(-) create mode 100644 database/entity/0087-add_dlt_users_table/DltTransaction.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 4737d95bc..75e9b2544 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -13,13 +13,18 @@ import { UserAccountDraft } from './model/UserAccountDraft' import { UserIdentifier } from './model/UserIdentifier' const sendTransaction = gql` - mutation ($input: TransactionInput!) { + mutation ($input: TransactionDraft!) { sendTransaction(data: $input) { error { message name } succeed + recipe { + createdAt + type + messageIdHex + } } } ` @@ -32,6 +37,11 @@ const registerAddress = gql` name } succeed + recipe { + createdAt + type + messageIdHex + } } } ` @@ -126,7 +136,6 @@ export class DltConnectorClient { amount: amountString, type: typeString, createdAt: transaction.balanceDate.toISOString(), - backendTransactionId: transaction.id, targetDate: transaction.creationDate?.toISOString(), }, } @@ -142,9 +151,14 @@ export class DltConnectorClient { if (result.error) { throw new Error(result.error.message) } + console.log(result) return result } catch (e) { - throw new LogError('Error send sending transaction to dlt-connector: ', e) + if (e instanceof Error) { + throw new LogError(`from dlt-connector: ${e.message}`) + } else { + throw new LogError('Exception sending transfer transaction to dlt-connector', e) + } } } @@ -172,11 +186,15 @@ export class DltConnectorClient { result, }) if (result.error) { - logger.error('Error sending register address transaction to dlt-connector', result.error) + throw new Error(result.error.message) } return result } catch (e) { - logger.error('Exception sending register address transaction to dlt-connector', e) + if (e instanceof Error) { + throw new LogError(`from dlt-connector: ${e.message}`) + } else { + throw new LogError('Exception sending register address transaction to dlt-connector', e) + } } } } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 6ddd15705..9dbbba1f1 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -66,7 +66,10 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/util/InterruptiveSleepManager' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' import { getTimeDurationObject, printTimeDuration } from '@/util/time' import random from 'random-bigint' diff --git a/backend/src/tasks/sendTransactionsToDltConnector.ts b/backend/src/tasks/sendTransactionsToDltConnector.ts index 26535e082..62c7c5ad7 100644 --- a/backend/src/tasks/sendTransactionsToDltConnector.ts +++ b/backend/src/tasks/sendTransactionsToDltConnector.ts @@ -33,31 +33,60 @@ export async function sendTransactionsToDltConnector(): Promise { while (true) { const pendingTransaction = await findNextPendingTransaction() if (pendingTransaction instanceof User) { - const result = await dltConnector.registerAddress(pendingTransaction) - if (result?.succeed && result.recipe) { - const dltUser = DltUser.create() - dltUser.userId = pendingTransaction.id - dltUser.messageId = result.recipe.messageIdHex - // wait until saved, necessary before next call to findNextPendingTransaction - await DltUser.save(dltUser) - logger.info('store dltUser: messageId=%s in dltTx=%d', dltUser.messageId, dltUser.id) + const dltUser = DltUser.create() + dltUser.userId = pendingTransaction.id + try { + const result = await dltConnector.registerAddress(pendingTransaction) + if (result?.succeed && result.recipe) { + dltUser.messageId = result.recipe.messageIdHex + } + } catch (e) { + if (e instanceof Error) { + dltUser.error = e.message + } else if (typeof e === 'string') { + dltUser.error = e + } + } + // wait until saved, necessary before next call to findNextPendingTransaction + await DltUser.save(dltUser) + if (dltUser.messageId) { + logger.info('store dltUser: messageId=%s, id=%d', dltUser.messageId, dltUser.id) + } else { + logger.error('store dltUser with error: id=%d, error=%s', dltUser.id, dltUser.error) } } else if (pendingTransaction instanceof Transaction) { - const result = await dltConnector.transmitTransaction(pendingTransaction) - if (result?.succeed && result.recipe) { - const dltTransaction = DltTransaction.create() - dltTransaction.transactionId = pendingTransaction.id - dltTransaction.messageId = result.recipe.messageIdHex - // wait until saved, necessary before next call to findNextPendingTransaction - await DltTransaction.save(dltTransaction) + const dltTransaction = DltTransaction.create() + dltTransaction.transactionId = pendingTransaction.id + try { + const result = await dltConnector.transmitTransaction(pendingTransaction) + if (result?.succeed && result.recipe) { + dltTransaction.messageId = result.recipe.messageIdHex + } else { + dltTransaction.error = 'skipped' + } + } catch (e) { + if (e instanceof Error) { + dltTransaction.error = e.message + } else if (typeof e === 'string') { + dltTransaction.error = e + } + } + // wait until saved, necessary before next call to findNextPendingTransaction + await DltTransaction.save(dltTransaction) + if (dltTransaction.messageId) { logger.info( - 'store dltTransaction: messageId=%s in dltTx=%d', + 'store dltTransaction: messageId=%s, id=%d', dltTransaction.messageId, dltTransaction.id, ) + } else { + logger.error( + 'store dltTransaction with error: id=%d, error=%s', + dltTransaction.id, + dltTransaction.error, + ) } } else { - // nothing to do, break inner loop and sleep until new work has arrived break } } @@ -72,22 +101,21 @@ export async function sendTransactionsToDltConnector(): Promise { } async function findNextPendingTransaction(): Promise { - const lastTransactionPromise: Promise = Transaction.createQueryBuilder() - .select() - .leftJoin(DltTransaction, 'dltTransaction', 'transaction.id = dltTransaction.transactionId') - .where('dltTransaction.transactionId IS NULL') + const lastTransactionPromise: Promise = Transaction.createQueryBuilder() + .leftJoin(DltTransaction, 'dltTransaction', 'Transaction.id = dltTransaction.transactionId') + .where('dltTransaction.transaction_id IS NULL') // eslint-disable-next-line camelcase - .orderBy({ balance_date: 'ASC', id: 'ASC' }) + .orderBy({ balance_date: 'ASC', Transaction_id: 'ASC' }) .limit(1) - .getRawOne() + .getOne() - const lastUserPromise: Promise = User.createQueryBuilder() - .leftJoin(DltUser, 'dltUser', 'user.id = dltUser.userId') - .where('dltUser.userId IS NULL') + const lastUserPromise: Promise = User.createQueryBuilder() + .leftJoin(DltUser, 'dltUser', 'User.id = dltUser.userId') + .where('dltUser.user_id IS NULL') // eslint-disable-next-line camelcase - .orderBy({ created_at: 'ASC', id: 'ASC' }) + .orderBy({ User_created_at: 'ASC', User_id: 'ASC' }) .limit(1) - .getRawOne() + .getOne() const results = await Promise.all([lastTransactionPromise, lastUserPromise]) if (results[0] && results[1]) { diff --git a/database/entity/0087-add_dlt_users_table/DltTransaction.ts b/database/entity/0087-add_dlt_users_table/DltTransaction.ts new file mode 100644 index 000000000..653077bac --- /dev/null +++ b/database/entity/0087-add_dlt_users_table/DltTransaction.ts @@ -0,0 +1,36 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' +import { Transaction } from '../Transaction' + +@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class DltTransaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: false }) + transactionId: number + + @Column({ + name: 'message_id', + length: 64, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + messageId: string + + @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) + verified: boolean + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) + verifiedAt: Date | null + + @Column({ name: 'error', type: 'text', nullable: true }) + error: string | null + + @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) + @JoinColumn({ name: 'transaction_id' }) + transaction?: Transaction | null +} diff --git a/database/entity/0087-add_dlt_users_table/DltUser.ts b/database/entity/0087-add_dlt_users_table/DltUser.ts index ca916e128..483437d58 100644 --- a/database/entity/0087-add_dlt_users_table/DltUser.ts +++ b/database/entity/0087-add_dlt_users_table/DltUser.ts @@ -27,6 +27,9 @@ export class DltUser extends BaseEntity { @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) verifiedAt: Date | null + @Column({ name: 'error', type: 'text', nullable: true }) + error: string | null + @OneToOne(() => User, (user) => user.dltUser) @JoinColumn({ name: 'user_id' }) user?: User | null diff --git a/database/entity/DltTransaction.ts b/database/entity/DltTransaction.ts index d9c03306c..31c21d583 100644 --- a/database/entity/DltTransaction.ts +++ b/database/entity/DltTransaction.ts @@ -1 +1 @@ -export { DltTransaction } from './0070-add_dlt_transactions_table/DltTransaction' +export { DltTransaction } from './0087-add_dlt_users_table/DltTransaction' diff --git a/database/migrations/0087-add_dlt_users_table.ts b/database/migrations/0087-add_dlt_users_table.ts index fdb310c67..95f5c2ca2 100644 --- a/database/migrations/0087-add_dlt_users_table.ts +++ b/database/migrations/0087-add_dlt_users_table.ts @@ -3,17 +3,28 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { await queryFn(` - CREATE TABLE dlt_users ( - id int unsigned NOT NULL AUTO_INCREMENT, - user_id int(10) unsigned NOT NULL, - message_id varchar(64) NULL DEFAULT NULL, - verified tinyint(4) NOT NULL DEFAULT 0, - created_at datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - verified_at datetime(3), + CREATE TABLE \`dlt_users\` ( + \`id\` int unsigned NOT NULL AUTO_INCREMENT, + \`user_id\` int(10) unsigned NOT NULL, + \`message_id\` varchar(64) NULL DEFAULT NULL, + \`verified\` tinyint(4) NOT NULL DEFAULT 0, + \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + \`verified_at\` datetime(3), + \`error\` text NULL DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + + await queryFn( + 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transactions_id` TO `transaction_id`;', + ) + await queryFn('ALTER TABLE `dlt_transactions` ADD COLUMN `error` text NULL DEFAULT NULL;') } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(`DROP TABLE dlt_users;`) + await queryFn(`DROP TABLE \`dlt_users\`;`) + + await queryFn( + 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transaction_id` TO `transactions_id`;', + ) + await queryFn('ALTER TABLE `dlt_transactions` DROP COLUMN `error`;') } diff --git a/dlt-connector/src/client/GradidoNode.ts b/dlt-connector/src/client/GradidoNode.ts index 92a211768..a33e5adc2 100644 --- a/dlt-connector/src/client/GradidoNode.ts +++ b/dlt-connector/src/client/GradidoNode.ts @@ -6,7 +6,7 @@ import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrp import { CONFIG } from '@/config' import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { confirmedTransactionFromBase64, getEnumValue } from '@/utils/typeConverter' +import { confirmedTransactionFromBase64 } from '@/utils/typeConverter' const client = new JsonRpcClient({ url: CONFIG.NODE_SERVER_URL, diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 59e1ecafd..d1fa48c3c 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,8 +1,8 @@ // https://www.npmjs.com/package/@apollo/protobufjs import { InputTransactionType } from '@enum/InputTransactionType' import { isValidDateString, isValidNumberString } from '@validator/DateString' -import { IsEnum, IsObject, IsPositive, ValidateNested } from 'class-validator' -import { InputType, Field, Int } from 'type-graphql' +import { IsEnum, IsObject, ValidateNested } from 'class-validator' +import { InputType, Field } from 'type-graphql' import { UserIdentifier } from './UserIdentifier' @@ -18,10 +18,6 @@ export class TransactionDraft { @ValidateNested() linkedUser: UserIdentifier - @Field(() => Int) - @IsPositive() - backendTransactionId: number - @Field(() => String) @isValidNumberString() amount: string diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index c025296fd..ac5366127 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -72,9 +72,21 @@ async function main() { const communityDraft = await backend.getHomeCommunityDraft() KeyPairCacheManager.getInstance().setHomeCommunityUUID(communityDraft.uuid) + logger.info('home community topic: %s', uuid4ToHash(communityDraft.uuid).convertToHex()) + logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) // ask gradido node if community blockchain was created - const firstTransaction = await getTransaction(1, uuid4ToHash(communityDraft.uuid).convertToHex()) - if (!firstTransaction) { + try { + const firstTransaction = await getTransaction( + 1, + uuid4ToHash(communityDraft.uuid).convertToHex(), + ) + if (!firstTransaction) { + // if not exist, create community root transaction + await SendToIotaContext(communityDraft) + } + } catch (e) { + // eslint-disable-next-line no-console + // console.log('error requesting gradido node: ', e) // if not exist, create community root transaction await SendToIotaContext(communityDraft) } diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index 0e80e19a4..b7a074a7a 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -29,6 +29,7 @@ export class CreationTransactionRole extends AbstractTransactionRole { } builder .setCreatedAt(new Date(this.self.createdAt)) + .setMemo('dummy memo for creation') .setTransactionCreation( new TransferAmount(recipientKeyPair.getPublicKey(), this.self.amount.toString()), new Date(this.self.targetDate), diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index c26f8c61f..e0749f002 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -26,6 +26,7 @@ export class TransferTransactionRole extends AbstractTransactionRole { const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) builder .setCreatedAt(new Date(this.self.createdAt)) + .setMemo('dummy memo for transfer') .setTransactionTransfer( new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), recipientKeyPair.getPublicKey(), diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index 655a9ab9e..b68f6d746 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -15,7 +15,6 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { return { user: new UserIdentifierLoggingView(this.self.user).toJSON(), linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), - backendTransactionId: this.self.backendTransactionId, amount: Number(this.self.amount), type: getEnumValue(InputTransactionType, this.self.type), createdAt: this.self.createdAt, From 93883ae9f26bcf6a4c20ef564291238cda247542 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 7 Nov 2024 17:35:37 +0100 Subject: [PATCH 013/226] fix and refactor dlt --- backend/package.json | 1 + .../apis/dltConnector/DltConnectorClient.ts | 138 +++++++---------- .../dltConnector/model/TransactionDraft.ts | 38 +++++ .../dltConnector/model/UserAccountDraft.ts | 10 +- .../apis/dltConnector/model/UserIdentifier.ts | 8 +- .../sendTransactionsToDltConnector.test.ts | 0 .../sendTransactionsToDltConnector.ts | 142 ++++++++++++++++++ .../resolver/TransactionLinkResolver.ts | 2 +- backend/src/index.ts | 2 +- .../tasks/sendTransactionsToDltConnector.ts | 129 ---------------- backend/yarn.lock | 17 +++ .../src/graphql/input/TransactionDraft.ts | 5 +- .../src/graphql/input/UserAccountDraft.ts | 3 +- .../src/graphql/model/TransactionResult.ts | 2 +- .../graphql/resolver/TransactionsResolver.ts | 3 +- .../src/graphql/validator/DateString.ts | 2 +- .../KeyPairCalculation.context.ts | 2 +- dlt-connector/yarn.lock | 41 ++++- 18 files changed, 321 insertions(+), 224 deletions(-) create mode 100755 backend/src/apis/dltConnector/model/TransactionDraft.ts rename backend/src/{tasks => apis/dltConnector}/sendTransactionsToDltConnector.test.ts (100%) create mode 100644 backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts delete mode 100644 backend/src/tasks/sendTransactionsToDltConnector.ts diff --git a/backend/package.json b/backend/package.json index ba45225a2..beb460fee 100644 --- a/backend/package.json +++ b/backend/package.json @@ -61,6 +61,7 @@ "@types/jest": "^27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^16.10.3", + "@types/node-fetch": "^2.6.11", "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "@types/uuid": "^8.3.4", diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 75e9b2544..3402e0844 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,16 +1,17 @@ import { Transaction as DbTransaction } from '@entity/Transaction' import { User } from '@entity/User' import { gql, GraphQLClient } from 'graphql-request' +// eslint-disable-next-line import/named, n/no-extraneous-import +import { FetchError } from 'node-fetch' import { CONFIG } from '@/config' import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -import { AccountType } from './enum/AccountType' +import { TransactionDraft } from './model/TransactionDraft' import { TransactionResult } from './model/TransactionResult' import { UserAccountDraft } from './model/UserAccountDraft' -import { UserIdentifier } from './model/UserIdentifier' const sendTransaction = gql` mutation ($input: TransactionDraft!) { @@ -46,17 +47,6 @@ const registerAddress = gql` } ` -// from ChatGPT -function getTransactionTypeString(id: TransactionTypeId): string { - const key = Object.keys(TransactionTypeId).find( - (key) => TransactionTypeId[key as keyof typeof TransactionTypeId] === id, - ) - if (key === undefined) { - throw new LogError('invalid transaction type id: ' + id.toString()) - } - return key -} - // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts /** @@ -109,92 +99,74 @@ export class DltConnectorClient { return DltConnectorClient.instance } + private getTransactionParams(input: DbTransaction | User): TransactionDraft | UserAccountDraft { + if (input instanceof DbTransaction) { + return new TransactionDraft(input) + } else if (input instanceof User) { + return new UserAccountDraft(input) + } + throw new LogError('transaction should be either Transaction or User Entity') + } + + private handleTransactionResult(result: TransactionResult) { + if (result.error) { + throw new Error(result.error.message) + } + return result + } + + private async sendTransaction(input: TransactionDraft) { + const { + data: { sendTransaction: result }, + } = await this.client.rawRequest<{ sendTransaction: TransactionResult }>(sendTransaction, { + input, + }) + return this.handleTransactionResult(result) + } + + private async registerAddress(input: UserAccountDraft) { + const { + data: { registerAddress: result }, + } = await this.client.rawRequest<{ registerAddress: TransactionResult }>(registerAddress, { + input, + }) + return this.handleTransactionResult(result) + } + /** * transmit transaction via dlt-connector to iota * and update dltTransactionId of transaction in db with iota message id */ public async transmitTransaction( - transaction: DbTransaction, + transaction: DbTransaction | User, ): Promise { // we don't need the receive transactions, there contain basically the same data as the send transactions - if ((transaction.typeId as TransactionTypeId) === TransactionTypeId.RECEIVE) { + if ( + transaction instanceof DbTransaction && + (transaction.typeId as TransactionTypeId) === TransactionTypeId.RECEIVE + ) { return } - const typeString = getTransactionTypeString(transaction.typeId) - // no negative values in dlt connector, gradido concept don't use negative values so the code don't use it too - const amountString = transaction.amount.abs().toString() - const params = { - input: { - user: { - uuid: transaction.userGradidoID, - communityUuid: transaction.userCommunityUuid, - } as UserIdentifier, - linkedUser: { - uuid: transaction.linkedUserGradidoID, - communityUuid: transaction.linkedUserCommunityUuid, - } as UserIdentifier, - amount: amountString, - type: typeString, - createdAt: transaction.balanceDate.toISOString(), - targetDate: transaction.creationDate?.toISOString(), - }, - } + + const input = this.getTransactionParams(transaction) try { - // TODO: add account nr for user after they have also more than one account in backend - logger.debug('transmit transaction to dlt connector', params) - const { - data: { sendTransaction: result }, - } = await this.client.rawRequest<{ sendTransaction: TransactionResult }>( - sendTransaction, - params, - ) - if (result.error) { - throw new Error(result.error.message) + logger.debug('transmit transaction or user to dlt connector', input) + if (input instanceof TransactionDraft) { + return await this.sendTransaction(input) + } else if (input instanceof UserAccountDraft) { + return await this.registerAddress(input) + } else { + throw new LogError('unhandled branch reached') } - console.log(result) - return result } catch (e) { - if (e instanceof Error) { + logger.error(e) + if (e instanceof FetchError) { + throw e + } else if (e instanceof Error) { throw new LogError(`from dlt-connector: ${e.message}`) } else { throw new LogError('Exception sending transfer transaction to dlt-connector', e) } } } - - public async registerAddress(dbUser: User): Promise { - const params = { - input: { - user: { - uuid: dbUser.gradidoID, - communityUuid: dbUser.communityUuid, - accountNr: 1, - } as UserIdentifier, - createdAt: dbUser.createdAt.toISOString(), - accountType: AccountType.COMMUNITY_HUMAN, - } as UserAccountDraft, - } - try { - const { - data: { registerAddress: result }, - } = await this.client.rawRequest<{ registerAddress: TransactionResult }>( - registerAddress, - params, - ) - logger.info('send register address transaction to dlt-connector', { - params, - result, - }) - if (result.error) { - throw new Error(result.error.message) - } - return result - } catch (e) { - if (e instanceof Error) { - throw new LogError(`from dlt-connector: ${e.message}`) - } else { - throw new LogError('Exception sending register address transaction to dlt-connector', e) - } - } - } } diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts new file mode 100755 index 000000000..e6b8f8d6d --- /dev/null +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -0,0 +1,38 @@ +// https://www.npmjs.com/package/@apollo/protobufjs +import { Transaction } from '@entity/Transaction' + +import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' +import { LogError } from '@/server/LogError' + +import { UserIdentifier } from './UserIdentifier' + +export class TransactionDraft { + user: UserIdentifier + linkedUser: UserIdentifier + amount: string + type: string + createdAt: string + // only for creation transactions + targetDate?: string + + constructor(transaction: Transaction) { + if ( + !transaction.linkedUserGradidoID || + !transaction.linkedUserCommunityUuid || + !transaction.userCommunityUuid + ) { + throw new LogError( + `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, + ) + } + this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) + this.linkedUser = new UserIdentifier( + transaction.linkedUserGradidoID, + transaction.linkedUserCommunityUuid, + ) + this.amount = transaction.amount.abs().toString() + this.type = TransactionTypeId[transaction.typeId] + this.createdAt = transaction.balanceDate.toISOString() + this.targetDate = transaction.creationDate?.toISOString() + } +} diff --git a/backend/src/apis/dltConnector/model/UserAccountDraft.ts b/backend/src/apis/dltConnector/model/UserAccountDraft.ts index f4aff4cb4..dc52065d1 100644 --- a/backend/src/apis/dltConnector/model/UserAccountDraft.ts +++ b/backend/src/apis/dltConnector/model/UserAccountDraft.ts @@ -1,9 +1,17 @@ +import { User } from '@entity/User' + import { AccountType } from '@/apis/dltConnector/enum/AccountType' import { UserIdentifier } from './UserIdentifier' -export interface UserAccountDraft { +export class UserAccountDraft { user: UserIdentifier createdAt: string accountType: AccountType + + constructor(user: User) { + this.user = new UserIdentifier(user.gradidoID, user.communityUuid) + this.createdAt = user.createdAt.toISOString() + this.accountType = AccountType.COMMUNITY_HUMAN + } } diff --git a/backend/src/apis/dltConnector/model/UserIdentifier.ts b/backend/src/apis/dltConnector/model/UserIdentifier.ts index e265593be..1824d17f3 100644 --- a/backend/src/apis/dltConnector/model/UserIdentifier.ts +++ b/backend/src/apis/dltConnector/model/UserIdentifier.ts @@ -1,5 +1,11 @@ -export interface UserIdentifier { +export class UserIdentifier { uuid: string communityUuid: string accountNr?: number + + constructor(uuid: string, communityUuid: string, accountNr?: number) { + this.uuid = uuid + this.communityUuid = communityUuid + this.accountNr = accountNr + } } diff --git a/backend/src/tasks/sendTransactionsToDltConnector.test.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts similarity index 100% rename from backend/src/tasks/sendTransactionsToDltConnector.test.ts rename to backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts new file mode 100644 index 000000000..36974b5cf --- /dev/null +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -0,0 +1,142 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { DltUser } from '@entity/DltUser' +import { Transaction } from '@entity/Transaction' +import { User } from '@entity/User' +// eslint-disable-next-line import/named, n/no-extraneous-import +import { FetchError } from 'node-fetch' + +import { DltConnectorClient } from '@dltConnector/DltConnectorClient' + +import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' +import { backendLogger as logger } from '@/server/logger' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' + +let isLoopRunning = true + +export const stopSendTransactionsToDltConnector = (): void => { + isLoopRunning = false +} + +function logTransactionResult( + type: 'dltUser' | 'dltTransaction', + data: { id: number; messageId: string; error: string | null }, +): void { + if (data.error) { + logger.error(`Store ${type} with error: id=${data.id}, error=${data.error}`) + } else { + logger.info(`Store ${type}: messageId=${data.messageId}, id=${data.id}`) + } +} + +async function saveTransactionResult( + pendingTransaction: User | Transaction, + messageId: string, + error: string | null, +): Promise { + if (pendingTransaction instanceof User) { + const dltUser = DltUser.create() + dltUser.userId = pendingTransaction.id + dltUser.messageId = messageId + dltUser.error = error + await DltUser.save(dltUser) + logTransactionResult('dltUser', dltUser) + } else if (pendingTransaction instanceof Transaction) { + const dltTransaction = DltTransaction.create() + dltTransaction.transactionId = pendingTransaction.id + dltTransaction.messageId = messageId + dltTransaction.error = error + await DltTransaction.save(dltTransaction) + logTransactionResult('dltTransaction', dltTransaction) + } +} + +async function findNextPendingTransaction(): Promise { + const lastTransactionPromise: Promise = Transaction.createQueryBuilder() + .leftJoin(DltTransaction, 'dltTransaction', 'Transaction.id = dltTransaction.transactionId') + .where('dltTransaction.transaction_id IS NULL') + // eslint-disable-next-line camelcase + .orderBy({ balance_date: 'ASC', Transaction_id: 'ASC' }) + .limit(1) + .getOne() + + const lastUserPromise: Promise = User.createQueryBuilder() + .leftJoin(DltUser, 'dltUser', 'User.id = dltUser.userId') + .where('dltUser.user_id IS NULL') + // eslint-disable-next-line camelcase + .orderBy({ User_created_at: 'ASC', User_id: 'ASC' }) + .limit(1) + .getOne() + + const results = await Promise.all([lastTransactionPromise, lastUserPromise]) + if (results[0] && results[1]) { + return results[0].balanceDate < results[1].createdAt ? results[0] : results[1] + } else if (results[0]) { + return results[0] + } else if (results[1]) { + return results[1] + } + return null +} + +async function processPendingTransactions(dltConnector: DltConnectorClient): Promise { + let pendingTransaction: Transaction | User | null = null + while ((pendingTransaction = await findNextPendingTransaction())) { + let result: TransactionResult | undefined + let messageId = '' + let error: string | null = null + + try { + result = await dltConnector.transmitTransaction(pendingTransaction) + if (result?.succeed && result.recipe) { + messageId = result.recipe.messageIdHex + } else { + error = 'skipped' + } + } catch (e) { + if (e instanceof FetchError) { + throw e + } + error = e instanceof Error ? e.message : String(e) + } + + await saveTransactionResult(pendingTransaction, messageId, error) + } +} + +export async function sendTransactionsToDltConnector(): Promise { + const dltConnector = DltConnectorClient.getInstance() + + if (!dltConnector) { + logger.info('Sending to DltConnector currently not configured...') + isLoopRunning = false + return + } + + logger.info('Starting sendTransactionsToDltConnector task') + + // eslint-disable-next-line no-unmodified-loop-condition + while (isLoopRunning) { + try { + // return after no pending transactions are left + await processPendingTransactions(dltConnector) + await InterruptiveSleepManager.getInstance().sleep( + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, + 1000, + ) + } catch (e) { + // couldn't connect to dlt-connector? We wait + if (e instanceof FetchError) { + logger.error(`error connecting dlt-connector, wait 5 seconds before retry: ${String(e)}`) + await InterruptiveSleepManager.getInstance().sleep( + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, + 5000, + ) + } else { + logger.error(`Error while sending to DLT-connector or writing messageId`, e) + } + } + } +} diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 0ef7f0586..8a5c92cf4 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -38,7 +38,7 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' -import { sendTransactionsToDltConnector } from '../../tasks/sendTransactionsToDltConnector' +import { sendTransactionsToDltConnector } from '../../apis/dltConnector/sendTransactionsToDltConnector' import { executeTransaction } from './TransactionResolver' import { getUserCreation, validateContribution } from './util/creations' diff --git a/backend/src/index.ts b/backend/src/index.ts index 5cb3574e4..dd166d3d5 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,7 @@ import { CONFIG } from './config' import { startValidateCommunities } from './federation/validateCommunities' import { createServer } from './server/createServer' -import { sendTransactionsToDltConnector } from './tasks/sendTransactionsToDltConnector' +import { sendTransactionsToDltConnector } from './apis/dltConnector/sendTransactionsToDltConnector' async function main() { const { app } = await createServer() diff --git a/backend/src/tasks/sendTransactionsToDltConnector.ts b/backend/src/tasks/sendTransactionsToDltConnector.ts deleted file mode 100644 index 62c7c5ad7..000000000 --- a/backend/src/tasks/sendTransactionsToDltConnector.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { DltTransaction } from '@entity/DltTransaction' -import { DltUser } from '@entity/DltUser' -import { Transaction } from '@entity/Transaction' -import { User } from '@entity/User' - -import { DltConnectorClient } from '@dltConnector/DltConnectorClient' - -import { backendLogger as logger } from '@/server/logger' -import { - InterruptiveSleepManager, - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, -} from '@/util/InterruptiveSleepManager' - -let running = true - -export const stopSendTransactionsToDltConnector = (): void => { - running = false -} - -export async function sendTransactionsToDltConnector(): Promise { - const dltConnector = DltConnectorClient.getInstance() - if (!dltConnector) { - logger.info('sending to DltConnector currently not configured...') - running = false - return - } - logger.info('start sendTransactionsToDltConnector task') - - // eslint-disable-next-line no-unmodified-loop-condition - while (running) { - try { - // loop while work could be found - while (true) { - const pendingTransaction = await findNextPendingTransaction() - if (pendingTransaction instanceof User) { - const dltUser = DltUser.create() - dltUser.userId = pendingTransaction.id - try { - const result = await dltConnector.registerAddress(pendingTransaction) - if (result?.succeed && result.recipe) { - dltUser.messageId = result.recipe.messageIdHex - } - } catch (e) { - if (e instanceof Error) { - dltUser.error = e.message - } else if (typeof e === 'string') { - dltUser.error = e - } - } - // wait until saved, necessary before next call to findNextPendingTransaction - await DltUser.save(dltUser) - if (dltUser.messageId) { - logger.info('store dltUser: messageId=%s, id=%d', dltUser.messageId, dltUser.id) - } else { - logger.error('store dltUser with error: id=%d, error=%s', dltUser.id, dltUser.error) - } - } else if (pendingTransaction instanceof Transaction) { - const dltTransaction = DltTransaction.create() - dltTransaction.transactionId = pendingTransaction.id - try { - const result = await dltConnector.transmitTransaction(pendingTransaction) - if (result?.succeed && result.recipe) { - dltTransaction.messageId = result.recipe.messageIdHex - } else { - dltTransaction.error = 'skipped' - } - } catch (e) { - if (e instanceof Error) { - dltTransaction.error = e.message - } else if (typeof e === 'string') { - dltTransaction.error = e - } - } - // wait until saved, necessary before next call to findNextPendingTransaction - await DltTransaction.save(dltTransaction) - if (dltTransaction.messageId) { - logger.info( - 'store dltTransaction: messageId=%s, id=%d', - dltTransaction.messageId, - dltTransaction.id, - ) - } else { - logger.error( - 'store dltTransaction with error: id=%d, error=%s', - dltTransaction.id, - dltTransaction.error, - ) - } - } else { - break - } - } - await InterruptiveSleepManager.getInstance().sleep( - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, - 1000, - ) - } catch (e) { - logger.error(`error while sending to dlt-connector or writing messageId`, e) - } - } -} - -async function findNextPendingTransaction(): Promise { - const lastTransactionPromise: Promise = Transaction.createQueryBuilder() - .leftJoin(DltTransaction, 'dltTransaction', 'Transaction.id = dltTransaction.transactionId') - .where('dltTransaction.transaction_id IS NULL') - // eslint-disable-next-line camelcase - .orderBy({ balance_date: 'ASC', Transaction_id: 'ASC' }) - .limit(1) - .getOne() - - const lastUserPromise: Promise = User.createQueryBuilder() - .leftJoin(DltUser, 'dltUser', 'User.id = dltUser.userId') - .where('dltUser.user_id IS NULL') - // eslint-disable-next-line camelcase - .orderBy({ User_created_at: 'ASC', User_id: 'ASC' }) - .limit(1) - .getOne() - - const results = await Promise.all([lastTransactionPromise, lastUserPromise]) - if (results[0] && results[1]) { - return results[0].balanceDate < results[1].createdAt ? results[0] : results[1] - } else if (results[0]) { - return results[0] - } else if (results[1]) { - return results[1] - } - return null -} diff --git a/backend/yarn.lock b/backend/yarn.lock index 5c33b1ce8..9e32b7d8c 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1126,6 +1126,14 @@ dependencies: "@types/node" "*" +"@types/node-fetch@^2.6.11": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*", "@types/node@^16.10.3": version "16.10.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5" @@ -3417,6 +3425,15 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index d1fa48c3c..3f1f57a85 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,9 +1,10 @@ // https://www.npmjs.com/package/@apollo/protobufjs -import { InputTransactionType } from '@enum/InputTransactionType' -import { isValidDateString, isValidNumberString } from '@validator/DateString' import { IsEnum, IsObject, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' +import { InputTransactionType } from '@enum/InputTransactionType' +import { isValidDateString, isValidNumberString } from '@validator/DateString' + import { UserIdentifier } from './UserIdentifier' @InputType() diff --git a/dlt-connector/src/graphql/input/UserAccountDraft.ts b/dlt-connector/src/graphql/input/UserAccountDraft.ts index e10be9574..9ae544e32 100644 --- a/dlt-connector/src/graphql/input/UserAccountDraft.ts +++ b/dlt-connector/src/graphql/input/UserAccountDraft.ts @@ -1,9 +1,10 @@ // https://www.npmjs.com/package/@apollo/protobufjs -import { isValidDateString } from '@validator/DateString' import { IsEnum, IsObject, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' +import { isValidDateString } from '@validator/DateString' + import { AccountType } from '@/graphql/enum/AccountType' import { UserIdentifier } from './UserIdentifier' diff --git a/dlt-connector/src/graphql/model/TransactionResult.ts b/dlt-connector/src/graphql/model/TransactionResult.ts index 370c9827d..346920310 100644 --- a/dlt-connector/src/graphql/model/TransactionResult.ts +++ b/dlt-connector/src/graphql/model/TransactionResult.ts @@ -19,7 +19,7 @@ export class TransactionResult { @Field(() => TransactionError, { nullable: true }) error?: TransactionError - // if no error happend, the message id of the iota transaction + // if no error happened, the message id of the iota transaction @Field(() => TransactionRecipe, { nullable: true }) recipe?: TransactionRecipe diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 50636dee3..e5e537ad9 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,6 +1,7 @@ -import { TransactionDraft } from '@input/TransactionDraft' import { Resolver, Arg, Mutation } from 'type-graphql' +import { TransactionDraft } from '@input/TransactionDraft' + import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' import { TransactionError } from '../model/TransactionError' diff --git a/dlt-connector/src/graphql/validator/DateString.ts b/dlt-connector/src/graphql/validator/DateString.ts index 2be057194..0445c1bbe 100644 --- a/dlt-connector/src/graphql/validator/DateString.ts +++ b/dlt-connector/src/graphql/validator/DateString.ts @@ -38,4 +38,4 @@ export function isValidNumberString(validationOptions?: ValidationOptions) { }, }) } -} \ No newline at end of file +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index 8e6466df5..012168bb0 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -12,7 +12,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' /** * @DCI-Context - * Context for calculating key pair for signing transactions + * Context for calculating key pair for signing transactions */ export async function KeyPairCalculation(input: UserIdentifier | string): Promise { const cache = KeyPairCacheManager.getInstance() diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index c4f244816..1f60d65f2 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -1082,7 +1082,7 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/node-fetch@^2.6.1": +"@types/node-fetch@^2.6.1", "@types/node-fetch@^2.6.11": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== @@ -2112,6 +2112,11 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -2931,6 +2936,14 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -3050,6 +3063,13 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -4670,6 +4690,11 @@ node-api-headers@^1.1.0: resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.3.0.tgz#bb32c6b3e33fb0004bd93c66787bf00998c834ea" integrity sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg== +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4677,6 +4702,15 @@ node-fetch@^2.6.12, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-gyp-build@^4.8.1: version "4.8.2" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" @@ -6265,6 +6299,11 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" +web-streams-polyfill@^3.0.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 4ab8d6b83a73d45b5331a4f033d7c190c317984f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 7 Nov 2024 18:25:45 +0100 Subject: [PATCH 014/226] expand dltTransaction to integrate also user and transactionLink --- backend/src/config/index.ts | 2 +- .../0087-add_dlt_users_table/DltUser.ts | 3 +- .../0088-merge_dlt_tables/DltTransaction.ts | 52 +++++ .../0088-merge_dlt_tables/TransactionLink.ts | 74 +++++++ database/entity/0088-merge_dlt_tables/User.ts | 181 ++++++++++++++++++ database/entity/DltTransaction.ts | 2 +- database/entity/TransactionLink.ts | 2 +- database/entity/User.ts | 2 +- database/entity/index.ts | 2 - database/migrations/0088-merge_dlt_tables.ts | 33 ++++ dht-node/src/config/index.ts | 2 +- federation/src/config/index.ts | 2 +- 12 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 database/entity/0088-merge_dlt_tables/DltTransaction.ts create mode 100644 database/entity/0088-merge_dlt_tables/TransactionLink.ts create mode 100644 database/entity/0088-merge_dlt_tables/User.ts create mode 100644 database/migrations/0088-merge_dlt_tables.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 7ded1b8f4..37a654f8e 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0087-add_dlt_users_table', + DB_VERSION: '0088-merge_dlt_tables', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/database/entity/0087-add_dlt_users_table/DltUser.ts b/database/entity/0087-add_dlt_users_table/DltUser.ts index 483437d58..2b9dccb3f 100644 --- a/database/entity/0087-add_dlt_users_table/DltUser.ts +++ b/database/entity/0087-add_dlt_users_table/DltUser.ts @@ -1,5 +1,6 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' -import { User } from '../User' +// this Entity was removed in current code and isn't any longer compatible with user +import { User } from './User' @Entity('dlt_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class DltUser extends BaseEntity { diff --git a/database/entity/0088-merge_dlt_tables/DltTransaction.ts b/database/entity/0088-merge_dlt_tables/DltTransaction.ts new file mode 100644 index 000000000..6525c229d --- /dev/null +++ b/database/entity/0088-merge_dlt_tables/DltTransaction.ts @@ -0,0 +1,52 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' +import { Transaction } from '../Transaction' +import { User } from '../User' +import { TransactionLink } from '../TransactionLink' + +@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class DltTransaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: true }) + transactionId?: number | null + + @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true }) + userId?: number | null + + @Column({ name: 'transaction_link_id', type: 'int', unsigned: true, nullable: true }) + transactionLinkId?: number | null + + @Column({ + name: 'message_id', + length: 64, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + messageId: string + + @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) + verified: boolean + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) + verifiedAt: Date | null + + @Column({ name: 'error', type: 'text', nullable: true }) + error: string | null + + @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) + @JoinColumn({ name: 'transaction_id' }) + transaction?: Transaction | null + + @OneToOne(() => User, (user) => user.dltTransaction) + @JoinColumn({ name: 'user_id' }) + user?: User | null + + @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.dltTransaction) + @JoinColumn({ name: 'transaction_link_id' }) + transactionLink?: TransactionLink | null +} diff --git a/database/entity/0088-merge_dlt_tables/TransactionLink.ts b/database/entity/0088-merge_dlt_tables/TransactionLink.ts new file mode 100644 index 000000000..3258e346f --- /dev/null +++ b/database/entity/0088-merge_dlt_tables/TransactionLink.ts @@ -0,0 +1,74 @@ +import { Decimal } from 'decimal.js-light' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToOne, + JoinColumn, +} from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { DltTransaction } from '../DltTransaction' + +@Entity('transaction_links') +export class TransactionLink extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ unsigned: true, nullable: false }) + userId: number + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + amount: Decimal + + @Column({ + type: 'decimal', + name: 'hold_available_amount', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + holdAvailableAmount: Decimal + + @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) + memo: string + + @Column({ length: 24, nullable: false, collation: 'utf8mb4_unicode_ci' }) + code: string + + @Column({ + type: 'datetime', + nullable: false, + }) + createdAt: Date + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ + type: 'datetime', + nullable: false, + }) + validUntil: Date + + @Column({ + type: 'datetime', + nullable: true, + }) + redeemedAt: Date | null + + @Column({ type: 'int', unsigned: true, nullable: true }) + redeemedBy: number | null + + @OneToOne(() => DltTransaction, (dlt) => dlt.transactionLinkId) + @JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' }) + dltTransaction?: DltTransaction | null +} diff --git a/database/entity/0088-merge_dlt_tables/User.ts b/database/entity/0088-merge_dlt_tables/User.ts new file mode 100644 index 000000000..d133cdad8 --- /dev/null +++ b/database/entity/0088-merge_dlt_tables/User.ts @@ -0,0 +1,181 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, + OneToOne, + Geometry, + ManyToOne, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { UserContact } from '../UserContact' +import { UserRole } from '../UserRole' +import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' +import { Community } from '../Community' +import { DltTransaction } from '../DltTransaction' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ type: 'bool', default: false }) + foreign: boolean + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'community_uuid', + type: 'char', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + communityUuid: string + + @ManyToOne(() => Community, (community) => community.users) + @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) + community: Community | null + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) + @JoinColumn({ name: 'email_id' }) + emailContact: UserContact + + @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) + emailId: number | null + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) + gmsPublishName: number + + @Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) + humhubPublishName: number + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ + name: 'password_encryption_type', + type: 'int', + unsigned: true, + nullable: false, + default: 0, + }) + passwordEncryptionType: number + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ type: 'bool', default: false }) + hideAmountGDD: boolean + + @Column({ type: 'bool', default: false }) + hideAmountGDT: boolean + + @OneToMany(() => UserRole, (userRole) => userRole.user) + @JoinColumn({ name: 'user_id' }) + userRoles: UserRole[] + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ name: 'gms_allowed', type: 'bool', default: true }) + gmsAllowed: boolean + + @Column({ + name: 'location', + type: 'geometry', + default: null, + nullable: true, + transformer: GeometryTransformer, + }) + location: Geometry | null + + @Column({ + name: 'gms_publish_location', + type: 'int', + unsigned: true, + nullable: false, + default: 2, + }) + gmsPublishLocation: number + + @Column({ name: 'gms_registered', type: 'bool', default: false }) + gmsRegistered: boolean + + @Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true }) + gmsRegisteredAt: Date | null + + @Column({ name: 'humhub_allowed', type: 'bool', default: false }) + humhubAllowed: boolean + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] + + @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) + @JoinColumn({ name: 'user_id' }) + userContacts?: UserContact[] + + @OneToOne(() => DltTransaction, (dlt) => dlt.userId) + @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) + dltTransaction?: DltTransaction | null +} diff --git a/database/entity/DltTransaction.ts b/database/entity/DltTransaction.ts index 31c21d583..373e5f593 100644 --- a/database/entity/DltTransaction.ts +++ b/database/entity/DltTransaction.ts @@ -1 +1 @@ -export { DltTransaction } from './0087-add_dlt_users_table/DltTransaction' +export { DltTransaction } from './0088-merge_dlt_tables/DltTransaction' diff --git a/database/entity/TransactionLink.ts b/database/entity/TransactionLink.ts index a483f0171..ff69e101f 100644 --- a/database/entity/TransactionLink.ts +++ b/database/entity/TransactionLink.ts @@ -1 +1 @@ -export { TransactionLink } from './0031-remove_sendEmail_from_transaction_link/TransactionLink' +export { TransactionLink } from './0088-merge_dlt_tables/TransactionLink' diff --git a/database/entity/User.ts b/database/entity/User.ts index 5267c24cc..3836c683e 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0087-add_dlt_users_table/User' +export { User } from './0088-merge_dlt_tables/User' diff --git a/database/entity/index.ts b/database/entity/index.ts index a5a988490..3352abdb4 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -13,7 +13,6 @@ import { Community } from './Community' import { FederatedCommunity } from './FederatedCommunity' import { UserRole } from './UserRole' import { DltTransaction } from './DltTransaction' -import { DltUser } from './DltUser' import { PendingTransaction } from './0071-add-pending_transactions-table/PendingTransaction' export const entities = [ @@ -22,7 +21,6 @@ export const entities = [ ContributionLink, ContributionMessage, DltTransaction, - DltUser, Event, FederatedCommunity, LoginElopageBuys, diff --git a/database/migrations/0088-merge_dlt_tables.ts b/database/migrations/0088-merge_dlt_tables.ts new file mode 100644 index 000000000..7964ffd94 --- /dev/null +++ b/database/migrations/0088-merge_dlt_tables.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(`DROP TABLE \`dlt_users\`;`) + await queryFn(` + ALTER TABLE \`dlt_transactions\` + CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL, + ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, + ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`; + `) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(` + CREATE TABLE \`dlt_users\` ( + \`id\` int unsigned NOT NULL AUTO_INCREMENT, + \`user_id\` int(10) unsigned NOT NULL, + \`message_id\` varchar(64) NULL DEFAULT NULL, + \`verified\` tinyint(4) NOT NULL DEFAULT 0, + \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + \`verified_at\` datetime(3), + \`error\` text NULL DEFAULT NULL, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + + await queryFn(` + ALTER TABLE \`dlt_transactions\` + CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NOT NULL, + DROP COLUMN \`user_id\`, + DROP COLUMN \`transaction_link_id\`; + `) +} diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index f2dc456b4..e0e7f094c 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -4,7 +4,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0087-add_dlt_users_table', + DB_VERSION: '0088-merge_dlt_tables', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 4ada82244..61ac3471d 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0087-add_dlt_users_table', + DB_VERSION: '0088-merge_dlt_tables', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info From 4875621699cbd5de0a52a949e1f289e35bd2cc9f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 12 Nov 2024 21:15:36 +0100 Subject: [PATCH 015/226] fix error with loop, implement dlt support for linked transactions --- .../apis/dltConnector/DltConnectorClient.ts | 9 +- .../apis/dltConnector/model/IdentifierSeed.ts | 7 + .../dltConnector/model/TransactionDraft.ts | 52 ++++--- .../sendTransactionsToDltConnector.ts | 141 ++++++++++++------ .../resolver/TransactionLinkResolver.ts | 4 - backend/src/index.ts | 2 +- .../0088-merge_dlt_tables/TransactionLink.ts | 5 + database/entity/0088-merge_dlt_tables/User.ts | 5 + .../src/graphql/input/TransactionDraft.ts | 5 + .../DeferredTransferTransaction.role.ts | 39 +++++ .../sendToIota/TransferTransaction.role.ts | 2 +- 11 files changed, 194 insertions(+), 77 deletions(-) create mode 100644 backend/src/apis/dltConnector/model/IdentifierSeed.ts create mode 100644 dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 3402e0844..b8f2dbbe3 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,4 +1,5 @@ import { Transaction as DbTransaction } from '@entity/Transaction' +import { TransactionLink } from '@entity/TransactionLink' import { User } from '@entity/User' import { gql, GraphQLClient } from 'graphql-request' // eslint-disable-next-line import/named, n/no-extraneous-import @@ -99,8 +100,10 @@ export class DltConnectorClient { return DltConnectorClient.instance } - private getTransactionParams(input: DbTransaction | User): TransactionDraft | UserAccountDraft { - if (input instanceof DbTransaction) { + private getTransactionParams( + input: DbTransaction | User | TransactionLink, + ): TransactionDraft | UserAccountDraft { + if (input instanceof DbTransaction || input instanceof TransactionLink) { return new TransactionDraft(input) } else if (input instanceof User) { return new UserAccountDraft(input) @@ -138,7 +141,7 @@ export class DltConnectorClient { * and update dltTransactionId of transaction in db with iota message id */ public async transmitTransaction( - transaction: DbTransaction | User, + transaction: DbTransaction | User | TransactionLink, ): Promise { // we don't need the receive transactions, there contain basically the same data as the send transactions if ( diff --git a/backend/src/apis/dltConnector/model/IdentifierSeed.ts b/backend/src/apis/dltConnector/model/IdentifierSeed.ts new file mode 100644 index 000000000..c597d2797 --- /dev/null +++ b/backend/src/apis/dltConnector/model/IdentifierSeed.ts @@ -0,0 +1,7 @@ +export class IdentifierSeed { + seed: string + + constructor(seed: string) { + this.seed = seed + } +} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index e6b8f8d6d..7413969eb 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -1,38 +1,52 @@ // https://www.npmjs.com/package/@apollo/protobufjs import { Transaction } from '@entity/Transaction' +import { TransactionLink } from '@entity/TransactionLink' import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' +import { IdentifierSeed } from './IdentifierSeed' import { UserIdentifier } from './UserIdentifier' export class TransactionDraft { user: UserIdentifier - linkedUser: UserIdentifier + linkedUser: UserIdentifier | IdentifierSeed amount: string type: string createdAt: string // only for creation transactions targetDate?: string + // only for transaction links + timeoutDate?: string - constructor(transaction: Transaction) { - if ( - !transaction.linkedUserGradidoID || - !transaction.linkedUserCommunityUuid || - !transaction.userCommunityUuid - ) { - throw new LogError( - `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, - ) - } - this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) - this.linkedUser = new UserIdentifier( - transaction.linkedUserGradidoID, - transaction.linkedUserCommunityUuid, - ) + constructor(transaction: Transaction | TransactionLink) { this.amount = transaction.amount.abs().toString() - this.type = TransactionTypeId[transaction.typeId] - this.createdAt = transaction.balanceDate.toISOString() - this.targetDate = transaction.creationDate?.toISOString() + + if (transaction instanceof Transaction) { + if ( + !transaction.linkedUserGradidoID || + !transaction.linkedUserCommunityUuid || + !transaction.userCommunityUuid + ) { + throw new LogError( + `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, + ) + } + this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) + this.linkedUser = new UserIdentifier( + transaction.linkedUserGradidoID, + transaction.linkedUserCommunityUuid, + ) + this.createdAt = transaction.balanceDate.toISOString() + this.targetDate = transaction.creationDate?.toISOString() + this.type = TransactionTypeId[transaction.typeId] + } else if (transaction instanceof TransactionLink) { + const user = transaction.user + this.user = new UserIdentifier(user.gradidoID, user.communityUuid) + this.linkedUser = new IdentifierSeed(transaction.code) + this.createdAt = transaction.createdAt.toISOString() + this.type = TransactionTypeId[TransactionTypeId.LINK_SUMMARY] + this.timeoutDate = transaction.validUntil.toISOString() + } } } diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts index 36974b5cf..c9a192189 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -1,6 +1,9 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { backendLogger as logger } from '@/server/logger' +import { BaseEntity, EntityPropertyNotFoundError, EntityTarget, OrderByCondition, SelectQueryBuilder } from '@dbTools/typeorm' import { DltTransaction } from '@entity/DltTransaction' -import { DltUser } from '@entity/DltUser' import { Transaction } from '@entity/Transaction' +import { TransactionLink } from '@entity/TransactionLink' import { User } from '@entity/User' // eslint-disable-next-line import/named, n/no-extraneous-import import { FetchError } from 'node-fetch' @@ -8,11 +11,11 @@ import { FetchError } from 'node-fetch' import { DltConnectorClient } from '@dltConnector/DltConnectorClient' import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' -import { backendLogger as logger } from '@/server/logger' import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, } from '@/util/InterruptiveSleepManager' +import { LogError } from '@/server/LogError' let isLoopRunning = true @@ -20,70 +23,105 @@ export const stopSendTransactionsToDltConnector = (): void => { isLoopRunning = false } -function logTransactionResult( - type: 'dltUser' | 'dltTransaction', - data: { id: number; messageId: string; error: string | null }, -): void { +interface NextPendingTransactionQueries { + lastTransactionQuery: SelectQueryBuilder + lastUserQuery: SelectQueryBuilder + lastTransactionLinkQuery: SelectQueryBuilder +} + +function logTransactionResult(data: { id: number; messageId: string; error: string | null }): void { if (data.error) { - logger.error(`Store ${type} with error: id=${data.id}, error=${data.error}`) + logger.error(`Store dltTransaction with error: id=${data.id}, error=${data.error}`) } else { - logger.info(`Store ${type}: messageId=${data.messageId}, id=${data.id}`) + logger.info(`Store dltTransaction: messageId=${data.messageId}, id=${data.id}`) } } async function saveTransactionResult( - pendingTransaction: User | Transaction, + pendingTransaction: User | Transaction | TransactionLink, messageId: string, error: string | null, ): Promise { + const dltTransaction = DltTransaction.create() + dltTransaction.messageId = messageId + dltTransaction.error = error if (pendingTransaction instanceof User) { - const dltUser = DltUser.create() - dltUser.userId = pendingTransaction.id - dltUser.messageId = messageId - dltUser.error = error - await DltUser.save(dltUser) - logTransactionResult('dltUser', dltUser) + dltTransaction.userId = pendingTransaction.id } else if (pendingTransaction instanceof Transaction) { - const dltTransaction = DltTransaction.create() dltTransaction.transactionId = pendingTransaction.id - dltTransaction.messageId = messageId - dltTransaction.error = error - await DltTransaction.save(dltTransaction) - logTransactionResult('dltTransaction', dltTransaction) + } else if (pendingTransaction instanceof TransactionLink) { + dltTransaction.transactionLinkId = pendingTransaction.id } + await DltTransaction.save(dltTransaction) + logTransactionResult(dltTransaction) } -async function findNextPendingTransaction(): Promise { - const lastTransactionPromise: Promise = Transaction.createQueryBuilder() - .leftJoin(DltTransaction, 'dltTransaction', 'Transaction.id = dltTransaction.transactionId') - .where('dltTransaction.transaction_id IS NULL') - // eslint-disable-next-line camelcase - .orderBy({ balance_date: 'ASC', Transaction_id: 'ASC' }) - .limit(1) - .getOne() - - const lastUserPromise: Promise = User.createQueryBuilder() - .leftJoin(DltUser, 'dltUser', 'User.id = dltUser.userId') - .where('dltUser.user_id IS NULL') - // eslint-disable-next-line camelcase - .orderBy({ User_created_at: 'ASC', User_id: 'ASC' }) - .limit(1) - .getOne() - - const results = await Promise.all([lastTransactionPromise, lastUserPromise]) - if (results[0] && results[1]) { - return results[0].balanceDate < results[1].createdAt ? results[0] : results[1] - } else if (results[0]) { - return results[0] - } else if (results[1]) { - return results[1] +async function findNextPendingTransaction(): Promise { + // Helper function to avoid code repetition + const createQueryForPendingItems = ( + qb: SelectQueryBuilder, + joinCondition: string, + orderBy: OrderByCondition, + ): Promise => { + return qb + .leftJoin(DltTransaction, 'dltTransaction', joinCondition) + .where('dltTransaction.user_id IS NULL') + .andWhere('dltTransaction.transaction_id IS NULL') + .andWhere('dltTransaction.transaction_link_Id IS NULL') + .orderBy(orderBy) + .limit(1) + .getOne() } - return null + + const lastTransactionPromise = createQueryForPendingItems( + Transaction.createQueryBuilder(), + 'Transaction.id = dltTransaction.transactionId', + // eslint-disable-next-line camelcase + { balance_date: 'ASC', Transaction_id: 'ASC' }, + ) + + const lastUserPromise = createQueryForPendingItems( + User.createQueryBuilder(), + 'User.id = dltTransaction.userId', + // eslint-disable-next-line camelcase + { User_created_at: 'ASC', User_id: 'ASC' }, + ) + + const lastTransactionLinkPromise = createQueryForPendingItems( + TransactionLink.createQueryBuilder().leftJoinAndSelect('transactionLink.user', 'user'), + 'TransactionLink.id = dltTransaction.transactionLinkId', + // eslint-disable-next-line camelcase + { TransactionLinkId_created_at: 'ASC', User_id: 'ASC' }, + ) + + const results = await Promise.all([ + lastTransactionPromise, + lastUserPromise, + lastTransactionLinkPromise, + ]) + + results.sort((a, b) => { + const getTime = (input: Transaction | User | TransactionLink | null) => { + if (!input) return Infinity + if (input instanceof Transaction) { + return input.balanceDate.getTime() + } else if (input instanceof User || input instanceof TransactionLink) { + return input.createdAt.getTime() + } + return Infinity + } + return getTime(a) - getTime(b) + }) + return results[0] ?? null } async function processPendingTransactions(dltConnector: DltConnectorClient): Promise { - let pendingTransaction: Transaction | User | null = null - while ((pendingTransaction = await findNextPendingTransaction())) { + let pendingTransaction: Transaction | User | TransactionLink | null = null + do { + pendingTransaction = await findNextPendingTransaction() + if (!pendingTransaction) { + return + } let result: TransactionResult | undefined let messageId = '' let error: string | null = null @@ -103,7 +141,7 @@ async function processPendingTransactions(dltConnector: DltConnectorClient): Pro } await saveTransactionResult(pendingTransaction, messageId, error) - } + } while (pendingTransaction) } export async function sendTransactionsToDltConnector(): Promise { @@ -114,9 +152,11 @@ export async function sendTransactionsToDltConnector(): Promise { isLoopRunning = false return } - logger.info('Starting sendTransactionsToDltConnector task') + // define outside of loop for reuse and reducing gb collection + // const queries = getFindNextPendingTransactionQueries() + // eslint-disable-next-line no-unmodified-loop-condition while (isLoopRunning) { try { @@ -127,6 +167,9 @@ export async function sendTransactionsToDltConnector(): Promise { 1000, ) } catch (e) { + if (e instanceof EntityPropertyNotFoundError) { + throw new LogError(e.message, e.stack) + } // couldn't connect to dlt-connector? We wait if (e instanceof FetchError) { logger.error(`error connecting dlt-connector, wait 5 seconds before retry: ${String(e)}`) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 8a5c92cf4..88f84b6e2 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -38,8 +38,6 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' -import { sendTransactionsToDltConnector } from '../../apis/dltConnector/sendTransactionsToDltConnector' - import { executeTransaction } from './TransactionResolver' import { getUserCreation, validateContribution } from './util/creations' import { getLastTransaction } from './util/getLastTransaction' @@ -311,8 +309,6 @@ export class TransactionLinkResolver { } finally { releaseLock() } - // trigger to send transaction via dlt-connector - void sendTransactionsToDltConnector() return true } else { const now = new Date() diff --git a/backend/src/index.ts b/backend/src/index.ts index dd166d3d5..f2026a0f9 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,7 @@ +import { sendTransactionsToDltConnector } from './apis/dltConnector/sendTransactionsToDltConnector' import { CONFIG } from './config' import { startValidateCommunities } from './federation/validateCommunities' import { createServer } from './server/createServer' -import { sendTransactionsToDltConnector } from './apis/dltConnector/sendTransactionsToDltConnector' async function main() { const { app } = await createServer() diff --git a/database/entity/0088-merge_dlt_tables/TransactionLink.ts b/database/entity/0088-merge_dlt_tables/TransactionLink.ts index 3258e346f..72c80195b 100644 --- a/database/entity/0088-merge_dlt_tables/TransactionLink.ts +++ b/database/entity/0088-merge_dlt_tables/TransactionLink.ts @@ -10,6 +10,7 @@ import { } from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { DltTransaction } from '../DltTransaction' +import { User } from '../User' @Entity('transaction_links') export class TransactionLink extends BaseEntity { @@ -71,4 +72,8 @@ export class TransactionLink extends BaseEntity { @OneToOne(() => DltTransaction, (dlt) => dlt.transactionLinkId) @JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' }) dltTransaction?: DltTransaction | null + + @OneToOne(() => User, (user) => user.transactionLink) + @JoinColumn({ name: 'userId' }) + user: User } diff --git a/database/entity/0088-merge_dlt_tables/User.ts b/database/entity/0088-merge_dlt_tables/User.ts index d133cdad8..64a6261ab 100644 --- a/database/entity/0088-merge_dlt_tables/User.ts +++ b/database/entity/0088-merge_dlt_tables/User.ts @@ -17,6 +17,7 @@ import { UserRole } from '../UserRole' import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' import { Community } from '../Community' import { DltTransaction } from '../DltTransaction' +import { TransactionLink } from './TransactionLink' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -178,4 +179,8 @@ export class User extends BaseEntity { @OneToOne(() => DltTransaction, (dlt) => dlt.userId) @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) dltTransaction?: DltTransaction | null + + @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.userId) + @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) + transactionLink?: TransactionLink | null } diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 3f1f57a85..9a702aee3 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -35,4 +35,9 @@ export class TransactionDraft { @Field(() => String, { nullable: true }) @isValidDateString() targetDate?: string + + // only for transaction links + @Field(() => String, { nullable: true }) + @isValidDateString() + timeoutDate?: string } diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts new file mode 100644 index 000000000..48c025b09 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -0,0 +1,39 @@ +import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' + +import { LogError } from '@/server/LogError' +import { uuid4ToHash } from '@/utils/typeConverter' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { TransferTransactionRole } from './TransferTransaction.role' + +export class DeferredTransferTransactionRole extends TransferTransactionRole { + public async getGradidoTransactionBuilder(): Promise { + const builder = new GradidoTransactionBuilder() + const senderKeyPair = await KeyPairCalculation(this.self.user) + const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + if (!this.self.timeoutDate) { + throw new LogError('timeoutDate date missing for deferred transfer transaction') + } + builder + .setCreatedAt(new Date(this.self.createdAt)) + .setMemo('dummy memo for transfer') + .setDeferredTransfer( + new GradidoTransfer( + new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), + recipientKeyPair.getPublicKey(), + ), + new Date(this.self.timeoutDate), + ) + const senderCommunity = this.self.user.communityUuid + const recipientCommunity = this.self.linkedUser.communityUuid + if (senderCommunity !== recipientCommunity) { + // we have a cross group transaction + builder + .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) + .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) + } + builder.sign(senderKeyPair) + return builder + } +} diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index e0749f002..1e5dde5dd 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -8,7 +8,7 @@ import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.con import { AbstractTransactionRole } from './AbstractTransaction.role' export class TransferTransactionRole extends AbstractTransactionRole { - constructor(private self: TransactionDraft) { + constructor(protected self: TransactionDraft) { super() } From e691db05b74b79145e58d4a589460a53a26e19b6 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 13 Nov 2024 14:22:04 +0100 Subject: [PATCH 016/226] move code into interaction in backend, implement transaction link in dlt-connector --- .../dltConnector/DltConnectorClient.test.ts | 5 +- .../apis/dltConnector/DltConnectorClient.ts | 22 +-- .../AbstractTransactionToDlt.role.ts | 63 ++++++++ .../TransactionLinkToDlt.role.ts | 45 ++++++ .../transactionToDlt/TransactionToDlt.role.ts | 45 ++++++ .../transactionToDlt/UserToDlt.role.ts | 45 ++++++ .../transactionToDlt.context.ts | 65 +++++++++ .../sendTransactionsToDltConnector.ts | 136 +----------------- backend/src/util/InterruptiveSleep.ts | 10 +- backend/src/util/utilities.ts | 4 + .../src/graphql/input/IdentifierSeed.ts | 9 ++ .../src/graphql/input/TransactionDraft.ts | 3 +- .../KeyPairCalculation.context.ts | 71 ++++----- .../LinkedTransactionKeyPair.role.ts | 22 +++ .../sendToIota/CreationTransaction.role.ts | 11 +- .../DeferredTransferTransaction.role.ts | 24 ++-- .../sendToIota/TransferTransaction.role.ts | 9 ++ .../logging/TransactionDraftLogging.view.ts | 6 +- .../src/manager/KeyPairCacheManager.ts | 12 +- dlt-connector/yarn.lock | 41 +----- 20 files changed, 400 insertions(+), 248 deletions(-) create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts create mode 100644 dlt-connector/src/graphql/input/IdentifierSeed.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index d99093a1b..8169be112 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -14,6 +14,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { DltConnectorClient } from './DltConnectorClient' +import { TransactionDraft } from './model/TransactionDraft' let con: Connection @@ -113,7 +114,9 @@ describe('transmitTransaction', () => { const localTransaction = new DbTransaction() localTransaction.typeId = 12 try { - await DltConnectorClient.getInstance()?.transmitTransaction(localTransaction) + await DltConnectorClient.getInstance()?.transmitTransaction( + new TransactionDraft(localTransaction), + ) } catch (e) { expect(e).toMatchObject( new LogError('invalid transaction type id: ' + localTransaction.typeId.toString()), diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index b8f2dbbe3..f864bb652 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,6 +1,3 @@ -import { Transaction as DbTransaction } from '@entity/Transaction' -import { TransactionLink } from '@entity/TransactionLink' -import { User } from '@entity/User' import { gql, GraphQLClient } from 'graphql-request' // eslint-disable-next-line import/named, n/no-extraneous-import import { FetchError } from 'node-fetch' @@ -9,6 +6,7 @@ import { CONFIG } from '@/config' import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' +// eslint-disable-next-line import/named, n/no-extraneous-import import { TransactionDraft } from './model/TransactionDraft' import { TransactionResult } from './model/TransactionResult' @@ -100,17 +98,6 @@ export class DltConnectorClient { return DltConnectorClient.instance } - private getTransactionParams( - input: DbTransaction | User | TransactionLink, - ): TransactionDraft | UserAccountDraft { - if (input instanceof DbTransaction || input instanceof TransactionLink) { - return new TransactionDraft(input) - } else if (input instanceof User) { - return new UserAccountDraft(input) - } - throw new LogError('transaction should be either Transaction or User Entity') - } - private handleTransactionResult(result: TransactionResult) { if (result.error) { throw new Error(result.error.message) @@ -141,17 +128,16 @@ export class DltConnectorClient { * and update dltTransactionId of transaction in db with iota message id */ public async transmitTransaction( - transaction: DbTransaction | User | TransactionLink, + input: TransactionDraft | UserAccountDraft, ): Promise { // we don't need the receive transactions, there contain basically the same data as the send transactions if ( - transaction instanceof DbTransaction && - (transaction.typeId as TransactionTypeId) === TransactionTypeId.RECEIVE + input instanceof TransactionDraft && + TransactionTypeId[input.type as keyof typeof TransactionTypeId] === TransactionTypeId.RECEIVE ) { return } - const input = this.getTransactionParams(transaction) try { logger.debug('transmit transaction or user to dlt connector', input) if (input instanceof TransactionDraft) { diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts new file mode 100644 index 000000000..50296244e --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -0,0 +1,63 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from '@dbTools/typeorm' +import { DltTransaction } from '@entity/DltTransaction' + +import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' + +import { backendLogger as logger } from '@/server/logger' + +export abstract class AbstractTransactionToDltRole { + protected self: T | null + + // public interface + public abstract initWithLast(): Promise + public abstract getTimestamp(): number + public abstract convertToGraphqlInput(): TransactionDraft | UserAccountDraft + public getEntity(): T | null { + return this.self + } + + public async saveTransactionResult(messageId: string, error: string | null): Promise { + const dltTransaction = DltTransaction.create() + dltTransaction.messageId = messageId + dltTransaction.error = error + this.setJoinId(dltTransaction) + await DltTransaction.save(dltTransaction) + if (dltTransaction.error) { + logger.error( + `Store dltTransaction with error: id=${dltTransaction.id}, error=${dltTransaction.error}`, + ) + } else { + logger.info( + `Store dltTransaction: messageId=${dltTransaction.messageId}, id=${dltTransaction.id}`, + ) + } + } + + // intern + protected abstract setJoinId(dltTransaction: DltTransaction): void + + // helper + protected createQueryForPendingItems( + qb: SelectQueryBuilder, + joinCondition: string, + orderBy: OrderByCondition, + ): Promise { + return qb + .leftJoin(DltTransaction, 'dltTransaction', joinCondition) + .where('dltTransaction.user_id IS NULL') + .andWhere('dltTransaction.transaction_id IS NULL') + .andWhere('dltTransaction.transaction_link_Id IS NULL') + .orderBy(orderBy) + .limit(1) + .getOne() + } + + protected createDltTransactionEntry(messageId: string, error: string | null): DltTransaction { + const dltTransaction = DltTransaction.create() + dltTransaction.messageId = messageId + dltTransaction.error = error + return dltTransaction + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts new file mode 100644 index 000000000..a30d86f65 --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -0,0 +1,45 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { TransactionLink } from '@entity/TransactionLink' + +import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' + +import { LogError } from '@/server/LogError' + +import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' + +/** + * send transactionLink as Deferred Transfers + */ +export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { + async initWithLast(): Promise { + this.self = await this.createQueryForPendingItems( + TransactionLink.createQueryBuilder().leftJoinAndSelect('transactionLink.user', 'user'), + 'TransactionLink.id = dltTransaction.transactionLinkId', + // eslint-disable-next-line camelcase + { TransactionLinkId_created_at: 'ASC', User_id: 'ASC' }, + ) + return this + } + + public getTimestamp(): number { + if (!this.self) { + return Infinity + } + return this.self.createdAt.getTime() + } + + public convertToGraphqlInput(): TransactionDraft | UserAccountDraft { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction link') + } + return new TransactionDraft(this.self) + } + + protected setJoinId(dltTransaction: DltTransaction): void { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction link') + } + dltTransaction.transactionLinkId = this.self.id + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts new file mode 100644 index 000000000..f777f2683 --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts @@ -0,0 +1,45 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { Transaction } from '@entity/Transaction' + +import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' + +import { LogError } from '@/server/LogError' + +import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' + +/** + * send transfer and creations transactions to dlt connector as GradidoTransfer and GradidoCreation + */ +export class TransactionToDltRole extends AbstractTransactionToDltRole { + async initWithLast(): Promise { + this.self = await this.createQueryForPendingItems( + Transaction.createQueryBuilder(), + 'Transaction.id = dltTransaction.transactionId', + // eslint-disable-next-line camelcase + { balance_date: 'ASC', Transaction_id: 'ASC' }, + ) + return this + } + + public getTimestamp(): number { + if (!this.self) { + return Infinity + } + return this.self.balanceDate.getTime() + } + + public convertToGraphqlInput(): TransactionDraft | UserAccountDraft { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction') + } + return new TransactionDraft(this.self) + } + + protected setJoinId(dltTransaction: DltTransaction): void { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction') + } + dltTransaction.transactionId = this.self.id + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts new file mode 100644 index 000000000..fc3b0b2c3 --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts @@ -0,0 +1,45 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { User } from '@entity/User' + +import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' + +import { LogError } from '@/server/LogError' + +import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' + +/** + * send new user to dlt connector, will be made to RegisterAddress Transaction + */ +export class UserToDltRole extends AbstractTransactionToDltRole { + async initWithLast(): Promise { + this.self = await this.createQueryForPendingItems( + User.createQueryBuilder(), + 'User.id = dltTransaction.userId', + // eslint-disable-next-line camelcase + { User_created_at: 'ASC', User_id: 'ASC' }, + ) + return this + } + + public getTimestamp(): number { + if (!this.self) { + return Infinity + } + return this.self.createdAt.getTime() + } + + public convertToGraphqlInput(): TransactionDraft | UserAccountDraft { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction') + } + return new UserAccountDraft(this.self) + } + + protected setJoinId(dltTransaction: DltTransaction): void { + if (!this.self) { + throw new LogError('try to create dlt entry for empty user') + } + dltTransaction.userId = this.self.id + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts new file mode 100644 index 000000000..57281f96b --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -0,0 +1,65 @@ +import { Transaction } from '@entity/Transaction' +import { TransactionLink } from '@entity/TransactionLink' +import { User } from '@entity/User' +// eslint-disable-next-line import/named, n/no-extraneous-import +import { FetchError } from 'node-fetch' + +import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' +import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' + +import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' +import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' +import { TransactionToDltRole } from './TransactionToDlt.role' +import { UserToDltRole } from './UserToDlt.role' + +/** + * @DCI-Context + * Context for sending transactions to dlt connector, always the oldest not sended transaction first + */ +export async function transactionToDlt(dltConnector: DltConnectorClient): Promise { + async function findNextPendingTransaction(): Promise< + AbstractTransactionToDltRole + > { + // collect each oldest not sended entity from db and choose oldest + const results = await Promise.all([ + new TransactionToDltRole().initWithLast(), + new UserToDltRole().initWithLast(), + new TransactionLinkToDltRole().initWithLast(), + ]) + + // sort array to get oldest at first place + results.sort((a, b) => { + return a.getTimestamp() - b.getTimestamp() + }) + return results[0] + } + + while (true) { + const pendingTransactionRole = await findNextPendingTransaction() + const pendingTransaction = pendingTransactionRole.getEntity() + if (!pendingTransaction) { + break + } + let result: TransactionResult | undefined + let messageId = '' + let error: string | null = null + + try { + result = await dltConnector.transmitTransaction( + pendingTransactionRole.convertToGraphqlInput(), + ) + if (result?.succeed && result.recipe) { + messageId = result.recipe.messageIdHex + } else { + error = 'skipped' + } + } catch (e) { + if (e instanceof FetchError) { + throw e + } + error = e instanceof Error ? e.message : String(e) + } + + await pendingTransactionRole.saveTransactionResult(messageId, error) + } +} diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts index c9a192189..7e0abf0fa 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -1,21 +1,18 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { backendLogger as logger } from '@/server/logger' -import { BaseEntity, EntityPropertyNotFoundError, EntityTarget, OrderByCondition, SelectQueryBuilder } from '@dbTools/typeorm' -import { DltTransaction } from '@entity/DltTransaction' -import { Transaction } from '@entity/Transaction' -import { TransactionLink } from '@entity/TransactionLink' -import { User } from '@entity/User' +import { EntityPropertyNotFoundError } from '@dbTools/typeorm' // eslint-disable-next-line import/named, n/no-extraneous-import import { FetchError } from 'node-fetch' import { DltConnectorClient } from '@dltConnector/DltConnectorClient' -import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' +import { LogError } from '@/server/LogError' +import { backendLogger as logger } from '@/server/logger' import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, } from '@/util/InterruptiveSleepManager' -import { LogError } from '@/server/LogError' + +import { transactionToDlt } from './interaction/transactionToDlt/transactionToDlt.context' let isLoopRunning = true @@ -23,127 +20,6 @@ export const stopSendTransactionsToDltConnector = (): void => { isLoopRunning = false } -interface NextPendingTransactionQueries { - lastTransactionQuery: SelectQueryBuilder - lastUserQuery: SelectQueryBuilder - lastTransactionLinkQuery: SelectQueryBuilder -} - -function logTransactionResult(data: { id: number; messageId: string; error: string | null }): void { - if (data.error) { - logger.error(`Store dltTransaction with error: id=${data.id}, error=${data.error}`) - } else { - logger.info(`Store dltTransaction: messageId=${data.messageId}, id=${data.id}`) - } -} - -async function saveTransactionResult( - pendingTransaction: User | Transaction | TransactionLink, - messageId: string, - error: string | null, -): Promise { - const dltTransaction = DltTransaction.create() - dltTransaction.messageId = messageId - dltTransaction.error = error - if (pendingTransaction instanceof User) { - dltTransaction.userId = pendingTransaction.id - } else if (pendingTransaction instanceof Transaction) { - dltTransaction.transactionId = pendingTransaction.id - } else if (pendingTransaction instanceof TransactionLink) { - dltTransaction.transactionLinkId = pendingTransaction.id - } - await DltTransaction.save(dltTransaction) - logTransactionResult(dltTransaction) -} - -async function findNextPendingTransaction(): Promise { - // Helper function to avoid code repetition - const createQueryForPendingItems = ( - qb: SelectQueryBuilder, - joinCondition: string, - orderBy: OrderByCondition, - ): Promise => { - return qb - .leftJoin(DltTransaction, 'dltTransaction', joinCondition) - .where('dltTransaction.user_id IS NULL') - .andWhere('dltTransaction.transaction_id IS NULL') - .andWhere('dltTransaction.transaction_link_Id IS NULL') - .orderBy(orderBy) - .limit(1) - .getOne() - } - - const lastTransactionPromise = createQueryForPendingItems( - Transaction.createQueryBuilder(), - 'Transaction.id = dltTransaction.transactionId', - // eslint-disable-next-line camelcase - { balance_date: 'ASC', Transaction_id: 'ASC' }, - ) - - const lastUserPromise = createQueryForPendingItems( - User.createQueryBuilder(), - 'User.id = dltTransaction.userId', - // eslint-disable-next-line camelcase - { User_created_at: 'ASC', User_id: 'ASC' }, - ) - - const lastTransactionLinkPromise = createQueryForPendingItems( - TransactionLink.createQueryBuilder().leftJoinAndSelect('transactionLink.user', 'user'), - 'TransactionLink.id = dltTransaction.transactionLinkId', - // eslint-disable-next-line camelcase - { TransactionLinkId_created_at: 'ASC', User_id: 'ASC' }, - ) - - const results = await Promise.all([ - lastTransactionPromise, - lastUserPromise, - lastTransactionLinkPromise, - ]) - - results.sort((a, b) => { - const getTime = (input: Transaction | User | TransactionLink | null) => { - if (!input) return Infinity - if (input instanceof Transaction) { - return input.balanceDate.getTime() - } else if (input instanceof User || input instanceof TransactionLink) { - return input.createdAt.getTime() - } - return Infinity - } - return getTime(a) - getTime(b) - }) - return results[0] ?? null -} - -async function processPendingTransactions(dltConnector: DltConnectorClient): Promise { - let pendingTransaction: Transaction | User | TransactionLink | null = null - do { - pendingTransaction = await findNextPendingTransaction() - if (!pendingTransaction) { - return - } - let result: TransactionResult | undefined - let messageId = '' - let error: string | null = null - - try { - result = await dltConnector.transmitTransaction(pendingTransaction) - if (result?.succeed && result.recipe) { - messageId = result.recipe.messageIdHex - } else { - error = 'skipped' - } - } catch (e) { - if (e instanceof FetchError) { - throw e - } - error = e instanceof Error ? e.message : String(e) - } - - await saveTransactionResult(pendingTransaction, messageId, error) - } while (pendingTransaction) -} - export async function sendTransactionsToDltConnector(): Promise { const dltConnector = DltConnectorClient.getInstance() @@ -161,7 +37,7 @@ export async function sendTransactionsToDltConnector(): Promise { while (isLoopRunning) { try { // return after no pending transactions are left - await processPendingTransactions(dltConnector) + await transactionToDlt(dltConnector) await InterruptiveSleepManager.getInstance().sleep( TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, 1000, diff --git a/backend/src/util/InterruptiveSleep.ts b/backend/src/util/InterruptiveSleep.ts index c21e57db9..dc8ed5ae0 100644 --- a/backend/src/util/InterruptiveSleep.ts +++ b/backend/src/util/InterruptiveSleep.ts @@ -1,3 +1,5 @@ +import { delay } from './utilities' + /** * Sleep, that can be interrupted * call sleep only for msSteps and than check if interrupt was called @@ -14,17 +16,11 @@ export class InterruptiveSleep { this.interruptSleep = true } - private static _sleep(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms) - }) - } - public async sleep(ms: number): Promise { let waited = 0 this.interruptSleep = false while (waited < ms && !this.interruptSleep) { - await InterruptiveSleep._sleep(this.msSteps) + await delay(this.msSteps) waited += this.msSteps } } diff --git a/backend/src/util/utilities.ts b/backend/src/util/utilities.ts index 905cce686..4f45af023 100644 --- a/backend/src/util/utilities.ts +++ b/backend/src/util/utilities.ts @@ -1,3 +1,5 @@ +import { promisify } from 'util' + import { Decimal } from 'decimal.js-light' import i18n from 'i18n' @@ -30,6 +32,8 @@ export function resetInterface>(obj: T): T { return obj } +export const delay = promisify(setTimeout) + export const ensureUrlEndsWithSlash = (url: string): string => { return url.endsWith('/') ? url : url.concat('/') } diff --git a/dlt-connector/src/graphql/input/IdentifierSeed.ts b/dlt-connector/src/graphql/input/IdentifierSeed.ts new file mode 100644 index 000000000..41e7a31cd --- /dev/null +++ b/dlt-connector/src/graphql/input/IdentifierSeed.ts @@ -0,0 +1,9 @@ +import { IsString } from 'class-validator' +import { InputType, Field } from 'type-graphql' + +@InputType() +export class IdentifierSeed { + @Field(() => String) + @IsString() + seed: string +} diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 9a702aee3..393d5da93 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -5,6 +5,7 @@ import { InputType, Field } from 'type-graphql' import { InputTransactionType } from '@enum/InputTransactionType' import { isValidDateString, isValidNumberString } from '@validator/DateString' +import { IdentifierSeed } from './IdentifierSeed' import { UserIdentifier } from './UserIdentifier' @InputType() @@ -17,7 +18,7 @@ export class TransactionDraft { @Field(() => UserIdentifier) @IsObject() @ValidateNested() - linkedUser: UserIdentifier + linkedUser: UserIdentifier | IdentifierSeed @Field(() => String) @isValidNumberString() diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index 012168bb0..ca54d8d16 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -1,12 +1,13 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' -import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' import { AccountKeyPairRole } from './AccountKeyPair.role' import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' +import { LinkedTransactionKeyPairRole } from './LinkedTransactionKeyPair.role' import { RemoteAccountKeyPairRole } from './RemoteAccountKeyPair.role' import { UserKeyPairRole } from './UserKeyPair.role' @@ -14,43 +15,49 @@ import { UserKeyPairRole } from './UserKeyPair.role' * @DCI-Context * Context for calculating key pair for signing transactions */ -export async function KeyPairCalculation(input: UserIdentifier | string): Promise { +export async function KeyPairCalculation( + input: UserIdentifier | string | IdentifierSeed, +): Promise { const cache = KeyPairCacheManager.getInstance() - const keyPair = cache.findKeyPair(input) + + // Try cache lookup first + let keyPair = cache.findKeyPair(input) if (keyPair) { return keyPair } - let communityUUID: string - if (input instanceof UserIdentifier) { - communityUUID = input.communityUuid - } else { - communityUUID = input - } - if (cache.getHomeCommunityUUID() !== communityUUID) { - // it isn't home community so we can only retrieve public keys - let role: AbstractRemoteKeyPairRole - if (input instanceof UserIdentifier) { - role = new RemoteAccountKeyPairRole(input) - } else { - role = new ForeignCommunityKeyPairRole(input) + const retrieveKeyPair = async ( + input: UserIdentifier | string | IdentifierSeed, + ): Promise => { + if (input instanceof IdentifierSeed) { + return new LinkedTransactionKeyPairRole(input.seed).generateKeyPair() } - const keyPair = await role.retrieveKeyPair() - cache.addKeyPair(input, keyPair) - return keyPair + + const communityUUID = input instanceof UserIdentifier ? input.communityUuid : input + + // If input does not belong to the home community, handle as remote key pair + if (cache.getHomeCommunityUUID() !== communityUUID) { + const role = + input instanceof UserIdentifier + ? new RemoteAccountKeyPairRole(input) + : new ForeignCommunityKeyPairRole(input) + return await role.retrieveKeyPair() + } + + let communityKeyPair = cache.findKeyPair(communityUUID) + if (!communityKeyPair) { + communityKeyPair = new HomeCommunityKeyPairRole().generateKeyPair() + cache.addKeyPair(communityUUID, communityKeyPair) + } + if (input instanceof UserIdentifier) { + const userKeyPair = new UserKeyPairRole(input, communityKeyPair).generateKeyPair() + const accountNr = input.accountNr ?? 1 + return new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() + } + return communityKeyPair } - let communityKeyPair = cache.findKeyPair(communityUUID) - if (!communityKeyPair) { - communityKeyPair = new HomeCommunityKeyPairRole().generateKeyPair() - cache.addKeyPair(communityUUID, communityKeyPair) - } - if (input instanceof UserIdentifier) { - const userKeyPair = new UserKeyPairRole(input, communityKeyPair).generateKeyPair() - const accountNr = input.accountNr ?? 1 - const accountKeyPair = new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() - cache.addKeyPair(input, accountKeyPair) - return accountKeyPair - } - return communityKeyPair + keyPair = await retrieveKeyPair(input) + cache.addKeyPair(input, keyPair) + return keyPair } diff --git a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts new file mode 100644 index 000000000..39a20dd7a --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts @@ -0,0 +1,22 @@ +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' + +import { LogError } from '@/server/LogError' + +import { AbstractKeyPairRole } from './AbstractKeyPair.role' + +export class LinkedTransactionKeyPairRole extends AbstractKeyPairRole { + public constructor(private seed: string) { + super() + } + + public generateKeyPair(): KeyPairEd25519 { + // seed is expected to be 24 bytes long, but we need 32 + // so hash the seed with blake2 and we have 32 Bytes + const hash = new MemoryBlock(this.seed).calculateHash() + const keyPair = KeyPairEd25519.create(hash) + if (!keyPair) { + throw new LogError('error creating Ed25519 KeyPair from seed', this.seed) + } + return keyPair + } +} diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index b7a074a7a..775c60cb7 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -1,5 +1,6 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { LogError } from '@/server/LogError' @@ -21,12 +22,16 @@ export class CreationTransactionRole extends AbstractTransactionRole { } public async getGradidoTransactionBuilder(): Promise { - const builder = new GradidoTransactionBuilder() - const recipientKeyPair = await KeyPairCalculation(this.self.user) - const signerKeyPair = await KeyPairCalculation(this.self.linkedUser) + if (this.self.linkedUser instanceof IdentifierSeed) { + throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') + } if (!this.self.targetDate) { throw new LogError('target date missing for creation transaction') } + const builder = new GradidoTransactionBuilder() + const recipientKeyPair = await KeyPairCalculation(this.self.user) + const signerKeyPair = await KeyPairCalculation(this.self.linkedUser) + builder .setCreatedAt(new Date(this.self.createdAt)) .setMemo('dummy memo for creation') diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 48c025b09..ff252f59d 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,20 +1,28 @@ import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { TransferTransactionRole } from './TransferTransaction.role' export class DeferredTransferTransactionRole extends TransferTransactionRole { + getRecipientCommunityUuid(): string { + throw new LogError('cannot be used as cross group transaction') + } + public async getGradidoTransactionBuilder(): Promise { - const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + if (this.self.linkedUser instanceof UserIdentifier) { + throw new LogError('invalid recipient, it is a UserIdentifier instead of a IdentifierSeed') + } if (!this.self.timeoutDate) { throw new LogError('timeoutDate date missing for deferred transfer transaction') } + const builder = new GradidoTransactionBuilder() + const senderKeyPair = await KeyPairCalculation(this.self.user) + const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + builder .setCreatedAt(new Date(this.self.createdAt)) .setMemo('dummy memo for transfer') @@ -25,14 +33,6 @@ export class DeferredTransferTransactionRole extends TransferTransactionRole { ), new Date(this.self.timeoutDate), ) - const senderCommunity = this.self.user.communityUuid - const recipientCommunity = this.self.linkedUser.communityUuid - if (senderCommunity !== recipientCommunity) { - // we have a cross group transaction - builder - .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) - .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) - } builder.sign(senderKeyPair) return builder } diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index 1e5dde5dd..16a2ec7ee 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -1,6 +1,8 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { LogError } from '@/server/LogError' import { uuid4ToHash } from '@/utils/typeConverter' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -17,10 +19,17 @@ export class TransferTransactionRole extends AbstractTransactionRole { } getRecipientCommunityUuid(): string { + if (this.self.linkedUser instanceof IdentifierSeed) { + throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') + } return this.self.linkedUser.communityUuid } public async getGradidoTransactionBuilder(): Promise { + if (this.self.linkedUser instanceof IdentifierSeed) { + throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') + } + const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation(this.self.user) const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index b68f6d746..8f9e11331 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -1,5 +1,6 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { getEnumValue } from '@/utils/typeConverter' import { AbstractLoggingView } from './AbstractLogging.view' @@ -14,7 +15,10 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { public toJSON(): any { return { user: new UserIdentifierLoggingView(this.self.user).toJSON(), - linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), + linkedUser: + this.self.linkedUser instanceof UserIdentifier + ? new UserIdentifierLoggingView(this.self.linkedUser).toJSON() + : 'seed', amount: Number(this.self.amount), type: getEnumValue(InputTransactionType, this.self.type), createdAt: this.self.createdAt, diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/manager/KeyPairCacheManager.ts index f5c11e388..844f5ad58 100644 --- a/dlt-connector/src/manager/KeyPairCacheManager.ts +++ b/dlt-connector/src/manager/KeyPairCacheManager.ts @@ -1,5 +1,6 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { LogError } from '@/server/LogError' @@ -44,11 +45,14 @@ export class KeyPairCacheManager { return this.homeCommunityUUID } - public findKeyPair(input: UserIdentifier | string): KeyPairEd25519 | undefined { + public findKeyPair(input: UserIdentifier | string | IdentifierSeed): KeyPairEd25519 | undefined { return this.cache.get(this.getKey(input)) } - public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void { + public addKeyPair( + input: UserIdentifier | string | IdentifierSeed, + keyPair: KeyPairEd25519, + ): void { const key = this.getKey(input) if (this.cache.has(key)) { throw new LogError('key already exist, cannot add', key) @@ -56,9 +60,11 @@ export class KeyPairCacheManager { this.cache.set(key, keyPair) } - protected getKey(input: UserIdentifier | string): string { + protected getKey(input: UserIdentifier | string | IdentifierSeed): string { if (input instanceof UserIdentifier) { return input.uuid + } else if (input instanceof IdentifierSeed) { + return input.seed } else { return input } diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index 1f60d65f2..c4f244816 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -1082,7 +1082,7 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/node-fetch@^2.6.1", "@types/node-fetch@^2.6.11": +"@types/node-fetch@^2.6.1": version "2.6.11" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== @@ -2112,11 +2112,6 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -data-uri-to-buffer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" - integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -2936,14 +2931,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -3063,13 +3050,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -4690,11 +4670,6 @@ node-api-headers@^1.1.0: resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.3.0.tgz#bb32c6b3e33fb0004bd93c66787bf00998c834ea" integrity sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg== -node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4702,15 +4677,6 @@ node-fetch@^2.6.12, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" - integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" - node-gyp-build@^4.8.1: version "4.8.2" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" @@ -6299,11 +6265,6 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" -web-streams-polyfill@^3.0.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" - integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From de162647e53489412288d55cd8e2fd44e9de5193 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 13 Nov 2024 14:55:34 +0100 Subject: [PATCH 017/226] fix error and error handling --- .../transactionToDlt/TransactionLinkToDlt.role.ts | 4 ++-- .../transactionToDlt/transactionToDlt.context.ts | 5 +---- .../dltConnector/sendTransactionsToDltConnector.ts | 12 +++++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index a30d86f65..1b0ac97e6 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -14,10 +14,10 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { async initWithLast(): Promise { this.self = await this.createQueryForPendingItems( - TransactionLink.createQueryBuilder().leftJoinAndSelect('transactionLink.user', 'user'), + TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'), 'TransactionLink.id = dltTransaction.transactionLinkId', // eslint-disable-next-line camelcase - { TransactionLinkId_created_at: 'ASC', User_id: 'ASC' }, + { TransactionLink_createdAt: 'ASC', User_id: 'ASC' }, ) return this } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts index 57281f96b..9e56eee81 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -1,3 +1,4 @@ +import { EntityPropertyNotFoundError, QueryFailedError, TypeORMError } from '@dbTools/typeorm' import { Transaction } from '@entity/Transaction' import { TransactionLink } from '@entity/TransactionLink' import { User } from '@entity/User' @@ -33,7 +34,6 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis }) return results[0] } - while (true) { const pendingTransactionRole = await findNextPendingTransaction() const pendingTransaction = pendingTransactionRole.getEntity() @@ -54,9 +54,6 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis error = 'skipped' } } catch (e) { - if (e instanceof FetchError) { - throw e - } error = e instanceof Error ? e.message : String(e) } diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts index 7e0abf0fa..98bbde864 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -1,5 +1,5 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { EntityPropertyNotFoundError } from '@dbTools/typeorm' +import { TypeORMError } from '@dbTools/typeorm' // eslint-disable-next-line import/named, n/no-extraneous-import import { FetchError } from 'node-fetch' @@ -43,9 +43,6 @@ export async function sendTransactionsToDltConnector(): Promise { 1000, ) } catch (e) { - if (e instanceof EntityPropertyNotFoundError) { - throw new LogError(e.message, e.stack) - } // couldn't connect to dlt-connector? We wait if (e instanceof FetchError) { logger.error(`error connecting dlt-connector, wait 5 seconds before retry: ${String(e)}`) @@ -54,7 +51,12 @@ export async function sendTransactionsToDltConnector(): Promise { 5000, ) } else { - logger.error(`Error while sending to DLT-connector or writing messageId`, e) + if (e instanceof TypeORMError) { + // seems to be a error in code, so let better stop here + throw new LogError(e.message, e.stack) + } else { + logger.error(`Error while sending to DLT-connector or writing messageId`, e) + } } } } From 7ddd1cf922d45dddde41521c725417a79e659e01 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 14 Nov 2024 08:50:39 +0100 Subject: [PATCH 018/226] refactored process --- .../apis/dltConnector/DltConnectorClient.ts | 31 +++++++++++- .../AbstractTransactionToDlt.role.ts | 7 ++- .../TransactionLinkToDlt.role.ts | 5 +- .../transactionToDlt/TransactionToDlt.role.ts | 3 +- .../transactionToDlt/UserToDlt.role.ts | 3 +- .../apis/dltConnector/model/IdentifierSeed.ts | 7 --- .../dltConnector/model/TransactionDraft.ts | 47 +++++++------------ .../model/TransactionLinkDraft.ts | 21 +++++++++ .../src/graphql/enum/InputTransactionType.ts | 3 ++ .../src/graphql/input/IdentifierSeed.ts | 8 +++- .../src/graphql/input/TransactionDraft.ts | 13 ++--- .../src/graphql/input/TransactionLinkDraft.ts | 30 ++++++++++++ .../graphql/resolver/TransactionsResolver.ts | 21 ++++++++- .../sendToIota/CreationTransaction.role.ts | 4 -- .../DeferredTransferTransaction.role.ts | 23 +++++---- .../sendToIota/SendToIota.context.ts | 6 ++- .../sendToIota/TransferTransaction.role.ts | 9 ---- 17 files changed, 161 insertions(+), 80 deletions(-) delete mode 100644 backend/src/apis/dltConnector/model/IdentifierSeed.ts create mode 100644 backend/src/apis/dltConnector/model/TransactionLinkDraft.ts create mode 100644 dlt-connector/src/graphql/input/TransactionLinkDraft.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index f864bb652..5bdf60c35 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -9,6 +9,7 @@ import { backendLogger as logger } from '@/server/logger' // eslint-disable-next-line import/named, n/no-extraneous-import import { TransactionDraft } from './model/TransactionDraft' +import { TransactionLinkDraft } from './model/TransactionLinkDraft' import { TransactionResult } from './model/TransactionResult' import { UserAccountDraft } from './model/UserAccountDraft' @@ -29,6 +30,23 @@ const sendTransaction = gql` } ` +const deferredTransfer = gql` + mutation ($input: TransactionLinkDraft!) { + deferredTransfer(data: $input) { + error { + message + name + } + succeed + recipe { + createdAt + type + messageIdHex + } + } + } +` + const registerAddress = gql` mutation ($input: UserAccountDraft!) { registerAddress(data: $input) { @@ -114,6 +132,15 @@ export class DltConnectorClient { return this.handleTransactionResult(result) } + private async deferredTransfer(input: TransactionLinkDraft) { + const { + data: { deferredTransfer: result }, + } = await this.client.rawRequest<{ deferredTransfer: TransactionResult }>(deferredTransfer, { + input, + }) + return this.handleTransactionResult(result) + } + private async registerAddress(input: UserAccountDraft) { const { data: { registerAddress: result }, @@ -128,7 +155,7 @@ export class DltConnectorClient { * and update dltTransactionId of transaction in db with iota message id */ public async transmitTransaction( - input: TransactionDraft | UserAccountDraft, + input: TransactionDraft | UserAccountDraft | TransactionLinkDraft, ): Promise { // we don't need the receive transactions, there contain basically the same data as the send transactions if ( @@ -144,6 +171,8 @@ export class DltConnectorClient { return await this.sendTransaction(input) } else if (input instanceof UserAccountDraft) { return await this.registerAddress(input) + } else if (input instanceof TransactionLinkDraft) { + return await this.deferredTransfer(input) } else { throw new LogError('unhandled branch reached') } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts index 50296244e..c1a73edd0 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -3,6 +3,7 @@ import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from '@dbTools/ty import { DltTransaction } from '@entity/DltTransaction' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft' import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' import { backendLogger as logger } from '@/server/logger' @@ -13,7 +14,11 @@ export abstract class AbstractTransactionToDltRole { // public interface public abstract initWithLast(): Promise public abstract getTimestamp(): number - public abstract convertToGraphqlInput(): TransactionDraft | UserAccountDraft + public abstract convertToGraphqlInput(): + | TransactionDraft + | UserAccountDraft + | TransactionLinkDraft + public getEntity(): T | null { return this.self } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 1b0ac97e6..5b1efdad6 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -2,6 +2,7 @@ import { DltTransaction } from '@entity/DltTransaction' import { TransactionLink } from '@entity/TransactionLink' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft' import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' import { LogError } from '@/server/LogError' @@ -29,11 +30,11 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { return this.self.createdAt.getTime() } - public convertToGraphqlInput(): TransactionDraft | UserAccountDraft { + public convertToGraphqlInput(): TransactionDraft | UserAccountDraft | TransactionLinkDraft { if (!this.self) { throw new LogError('try to create dlt entry for empty transaction') } diff --git a/backend/src/apis/dltConnector/model/IdentifierSeed.ts b/backend/src/apis/dltConnector/model/IdentifierSeed.ts deleted file mode 100644 index c597d2797..000000000 --- a/backend/src/apis/dltConnector/model/IdentifierSeed.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class IdentifierSeed { - seed: string - - constructor(seed: string) { - this.seed = seed - } -} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 7413969eb..e31003986 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -1,52 +1,39 @@ // https://www.npmjs.com/package/@apollo/protobufjs import { Transaction } from '@entity/Transaction' -import { TransactionLink } from '@entity/TransactionLink' import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { LogError } from '@/server/LogError' -import { IdentifierSeed } from './IdentifierSeed' import { UserIdentifier } from './UserIdentifier' export class TransactionDraft { user: UserIdentifier - linkedUser: UserIdentifier | IdentifierSeed + linkedUser: UserIdentifier amount: string type: string createdAt: string // only for creation transactions targetDate?: string - // only for transaction links - timeoutDate?: string - constructor(transaction: Transaction | TransactionLink) { + constructor(transaction: Transaction) { this.amount = transaction.amount.abs().toString() - if (transaction instanceof Transaction) { - if ( - !transaction.linkedUserGradidoID || - !transaction.linkedUserCommunityUuid || - !transaction.userCommunityUuid - ) { - throw new LogError( - `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, - ) - } - this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) - this.linkedUser = new UserIdentifier( - transaction.linkedUserGradidoID, - transaction.linkedUserCommunityUuid, + if ( + !transaction.linkedUserGradidoID || + !transaction.linkedUserCommunityUuid || + !transaction.userCommunityUuid + ) { + throw new LogError( + `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, ) - this.createdAt = transaction.balanceDate.toISOString() - this.targetDate = transaction.creationDate?.toISOString() - this.type = TransactionTypeId[transaction.typeId] - } else if (transaction instanceof TransactionLink) { - const user = transaction.user - this.user = new UserIdentifier(user.gradidoID, user.communityUuid) - this.linkedUser = new IdentifierSeed(transaction.code) - this.createdAt = transaction.createdAt.toISOString() - this.type = TransactionTypeId[TransactionTypeId.LINK_SUMMARY] - this.timeoutDate = transaction.validUntil.toISOString() } + this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) + this.linkedUser = new UserIdentifier( + transaction.linkedUserGradidoID, + transaction.linkedUserCommunityUuid, + ) + this.createdAt = transaction.balanceDate.toISOString() + this.targetDate = transaction.creationDate?.toISOString() + this.type = TransactionTypeId[transaction.typeId] } } diff --git a/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts b/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts new file mode 100644 index 000000000..1a12f552b --- /dev/null +++ b/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts @@ -0,0 +1,21 @@ +// https://www.npmjs.com/package/@apollo/protobufjs +import { TransactionLink } from '@entity/TransactionLink' + +import { UserIdentifier } from './UserIdentifier' + +export class TransactionLinkDraft { + user: UserIdentifier + seed: string + amount: string + createdAt: string + timeoutDate: string + + constructor(transaction: TransactionLink) { + this.amount = transaction.amount.abs().toString() + const user = transaction.user + this.user = new UserIdentifier(user.gradidoID, user.communityUuid) + this.seed = transaction.code + this.createdAt = transaction.createdAt.toISOString() + this.timeoutDate = transaction.validUntil.toISOString() + } +} diff --git a/dlt-connector/src/graphql/enum/InputTransactionType.ts b/dlt-connector/src/graphql/enum/InputTransactionType.ts index 41eeac6cb..94cd39ff3 100755 --- a/dlt-connector/src/graphql/enum/InputTransactionType.ts +++ b/dlt-connector/src/graphql/enum/InputTransactionType.ts @@ -6,6 +6,9 @@ export enum InputTransactionType { CREATION = 1, SEND = 2, RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, } registerEnumType(InputTransactionType, { diff --git a/dlt-connector/src/graphql/input/IdentifierSeed.ts b/dlt-connector/src/graphql/input/IdentifierSeed.ts index 41e7a31cd..f09ad2f8b 100644 --- a/dlt-connector/src/graphql/input/IdentifierSeed.ts +++ b/dlt-connector/src/graphql/input/IdentifierSeed.ts @@ -1,9 +1,15 @@ +// https://www.npmjs.com/package/@apollo/protobufjs + import { IsString } from 'class-validator' -import { InputType, Field } from 'type-graphql' +import { Field, InputType } from 'type-graphql' @InputType() export class IdentifierSeed { @Field(() => String) @IsString() seed: string + + constructor(seed: string) { + this.seed = seed + } } diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 393d5da93..d1fa48c3c 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,11 +1,9 @@ // https://www.npmjs.com/package/@apollo/protobufjs +import { InputTransactionType } from '@enum/InputTransactionType' +import { isValidDateString, isValidNumberString } from '@validator/DateString' import { IsEnum, IsObject, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' -import { InputTransactionType } from '@enum/InputTransactionType' -import { isValidDateString, isValidNumberString } from '@validator/DateString' - -import { IdentifierSeed } from './IdentifierSeed' import { UserIdentifier } from './UserIdentifier' @InputType() @@ -18,7 +16,7 @@ export class TransactionDraft { @Field(() => UserIdentifier) @IsObject() @ValidateNested() - linkedUser: UserIdentifier | IdentifierSeed + linkedUser: UserIdentifier @Field(() => String) @isValidNumberString() @@ -36,9 +34,4 @@ export class TransactionDraft { @Field(() => String, { nullable: true }) @isValidDateString() targetDate?: string - - // only for transaction links - @Field(() => String, { nullable: true }) - @isValidDateString() - timeoutDate?: string } diff --git a/dlt-connector/src/graphql/input/TransactionLinkDraft.ts b/dlt-connector/src/graphql/input/TransactionLinkDraft.ts new file mode 100644 index 000000000..7ac621e35 --- /dev/null +++ b/dlt-connector/src/graphql/input/TransactionLinkDraft.ts @@ -0,0 +1,30 @@ +// https://www.npmjs.com/package/@apollo/protobufjs +import { isValidDateString, isValidNumberString } from '@validator/DateString' +import { IsObject, IsString, ValidateNested } from 'class-validator' +import { InputType, Field } from 'type-graphql' + +import { UserIdentifier } from './UserIdentifier' + +@InputType() +export class TransactionLinkDraft { + @Field(() => UserIdentifier) + @IsObject() + @ValidateNested() + user: UserIdentifier + + @Field(() => String) + @IsString() + seed: string + + @Field(() => String) + @isValidNumberString() + amount: string + + @Field(() => String) + @isValidDateString() + createdAt: string + + @Field(() => String) + @isValidDateString() + timeoutDate: string +} diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index e5e537ad9..8d3d5970b 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,9 +1,9 @@ +import { TransactionLinkDraft } from '@input/TransactionLinkDraft' import { Resolver, Arg, Mutation } from 'type-graphql' -import { TransactionDraft } from '@input/TransactionDraft' - import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' +import { TransactionDraft } from '../input/TransactionDraft' import { TransactionError } from '../model/TransactionError' import { TransactionResult } from '../model/TransactionResult' @@ -25,4 +25,21 @@ export class TransactionResolver { } } } + + @Mutation(() => TransactionResult) + async deferredTransfer( + @Arg('data') + transactionLinkDraft: TransactionLinkDraft, + ): Promise { + try { + return await SendToIotaContext(transactionLinkDraft) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + if (error instanceof TransactionError) { + return new TransactionResult(error) + } else { + throw error + } + } + } } diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index 775c60cb7..c448a1704 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -1,6 +1,5 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { LogError } from '@/server/LogError' @@ -22,9 +21,6 @@ export class CreationTransactionRole extends AbstractTransactionRole { } public async getGradidoTransactionBuilder(): Promise { - if (this.self.linkedUser instanceof IdentifierSeed) { - throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') - } if (!this.self.targetDate) { throw new LogError('target date missing for creation transaction') } diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index ff252f59d..7a4c627a1 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,27 +1,30 @@ import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' +import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft' import { LogError } from '@/server/LogError' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' -import { TransferTransactionRole } from './TransferTransaction.role' +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class DeferredTransferTransactionRole extends AbstractTransactionRole { + constructor(protected self: TransactionLinkDraft) { + super() + } + + getSenderCommunityUuid(): string { + return this.self.user.communityUuid + } -export class DeferredTransferTransactionRole extends TransferTransactionRole { getRecipientCommunityUuid(): string { throw new LogError('cannot be used as cross group transaction') } public async getGradidoTransactionBuilder(): Promise { - if (this.self.linkedUser instanceof UserIdentifier) { - throw new LogError('invalid recipient, it is a UserIdentifier instead of a IdentifierSeed') - } - if (!this.self.timeoutDate) { - throw new LogError('timeoutDate date missing for deferred transfer transaction') - } const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + const recipientKeyPair = await KeyPairCalculation(new IdentifierSeed(this.self.seed)) builder .setCreatedAt(new Date(this.self.createdAt)) diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index a10a95c35..caf4df11f 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -12,6 +12,7 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft' import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { TransactionError } from '@/graphql/model/TransactionError' import { TransactionRecipe } from '@/graphql/model/TransactionRecipe' @@ -23,6 +24,7 @@ import { uuid4ToHash } from '@/utils/typeConverter' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' +import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' @@ -32,7 +34,7 @@ import { TransferTransactionRole } from './TransferTransaction.role' * send every transaction only once to iota! */ export async function SendToIotaContext( - input: TransactionDraft | UserAccountDraft | CommunityDraft, + input: TransactionDraft | UserAccountDraft | CommunityDraft | TransactionLinkDraft, ): Promise { const validate = (transaction: GradidoTransaction): void => { try { @@ -81,6 +83,8 @@ export async function SendToIotaContext( } else { throw new LogError('not supported transaction type') } + } else if (input instanceof TransactionLinkDraft) { + role = new DeferredTransferTransactionRole(input) } else if (input instanceof UserAccountDraft) { role = new RegisterAddressTransactionRole(input) } else if (input instanceof CommunityDraft) { diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index 16a2ec7ee..1e5dde5dd 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -1,8 +1,6 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { LogError } from '@/server/LogError' import { uuid4ToHash } from '@/utils/typeConverter' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -19,17 +17,10 @@ export class TransferTransactionRole extends AbstractTransactionRole { } getRecipientCommunityUuid(): string { - if (this.self.linkedUser instanceof IdentifierSeed) { - throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') - } return this.self.linkedUser.communityUuid } public async getGradidoTransactionBuilder(): Promise { - if (this.self.linkedUser instanceof IdentifierSeed) { - throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier') - } - const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation(this.self.user) const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) From a24ed8ef986e43ab71fe8bac151807a07d0d4d39 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 14 Nov 2024 11:20:43 +0100 Subject: [PATCH 019/226] refactor, pack in one graphql in put model, add redeeming transaction link in dlt --- .../dltConnector/DltConnectorClient.test.ts | 15 -- .../apis/dltConnector/DltConnectorClient.ts | 112 +---------- .../apis/dltConnector/enum/TransactionType.ts | 19 +- .../AbstractTransactionToDlt.role.ts | 10 +- .../TransactionLinkToDlt.role.ts | 20 +- .../transactionToDlt/TransactionToDlt.role.ts | 61 +++++- .../transactionToDlt/UserToDlt.role.ts | 17 +- .../transactionToDlt.context.ts | 25 +-- .../apis/dltConnector/model/CommunityUser.ts | 10 + .../apis/dltConnector/model/IdentifierSeed.ts | 9 + .../dltConnector/model/TransactionDraft.ts | 42 ++--- .../model/TransactionLinkDraft.ts | 21 --- .../dltConnector/model/UserAccountDraft.ts | 17 -- .../apis/dltConnector/model/UserIdentifier.ts | 20 +- .../0088-merge_dlt_tables/Transaction.ts | 176 ++++++++++++++++++ .../0088-merge_dlt_tables/TransactionLink.ts | 6 + database/entity/Transaction.ts | 2 +- .../logging/TransactionLinkLogging.view.ts | 35 ++++ database/logging/TransactionLogging.view.ts | 7 +- .../src/graphql/enum/InputTransactionType.ts | 12 +- .../src/graphql/input/CommunityDraft.ts | 3 +- .../src/graphql/input/CommunityUser.ts | 15 ++ .../src/graphql/input/TransactionDraft.ts | 22 ++- .../src/graphql/input/TransactionLinkDraft.ts | 30 --- .../src/graphql/input/UserAccountDraft.ts | 26 --- .../src/graphql/input/UserIdentifier.ts | 23 ++- .../src/graphql/resolver/AccountsResolver.ts | 23 +-- .../graphql/resolver/TransactionsResolver.ts | 18 -- .../KeyPairCalculation.context.ts | 14 +- .../RemoteAccountKeyPair.role.ts | 6 +- .../keyPairCalculation/UserKeyPair.role.ts | 6 +- .../sendToIota/CreationTransaction.role.ts | 22 ++- .../DeferredTransferTransaction.role.ts | 33 +++- .../RegisterAddressTransaction.role.ts | 22 ++- .../sendToIota/SendToIota.context.ts | 32 ++-- .../sendToIota/TransferTransaction.role.ts | 22 ++- .../src/logging/CommunityUserLogging.view.ts | 17 ++ .../src/logging/IdentifierSeedLogging.view.ts | 16 ++ .../src/logging/UserIdentifierLogging.view.ts | 8 +- .../src/manager/KeyPairCacheManager.ts | 21 ++- 40 files changed, 606 insertions(+), 409 deletions(-) create mode 100644 backend/src/apis/dltConnector/model/CommunityUser.ts create mode 100644 backend/src/apis/dltConnector/model/IdentifierSeed.ts delete mode 100644 backend/src/apis/dltConnector/model/TransactionLinkDraft.ts delete mode 100644 backend/src/apis/dltConnector/model/UserAccountDraft.ts create mode 100644 database/entity/0088-merge_dlt_tables/Transaction.ts create mode 100644 database/logging/TransactionLinkLogging.view.ts create mode 100644 dlt-connector/src/graphql/input/CommunityUser.ts delete mode 100644 dlt-connector/src/graphql/input/TransactionLinkDraft.ts delete mode 100644 dlt-connector/src/graphql/input/UserAccountDraft.ts create mode 100644 dlt-connector/src/logging/CommunityUserLogging.view.ts create mode 100644 dlt-connector/src/logging/IdentifierSeedLogging.view.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index 8169be112..5cd7c3269 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -109,21 +109,6 @@ describe('transmitTransaction', () => { expect(result).toBe(false) }) */ - - it('invalid transaction type', async () => { - const localTransaction = new DbTransaction() - localTransaction.typeId = 12 - try { - await DltConnectorClient.getInstance()?.transmitTransaction( - new TransactionDraft(localTransaction), - ) - } catch (e) { - expect(e).toMatchObject( - new LogError('invalid transaction type id: ' + localTransaction.typeId.toString()), - ) - } - }) - /* it.skip('should transmit the transaction and update the dltTransactionId in the database', async () => { await transaction.save() diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 5bdf60c35..a9a6557d5 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,17 +1,11 @@ import { gql, GraphQLClient } from 'graphql-request' -// eslint-disable-next-line import/named, n/no-extraneous-import -import { FetchError } from 'node-fetch' import { CONFIG } from '@/config' -import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' -import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' // eslint-disable-next-line import/named, n/no-extraneous-import import { TransactionDraft } from './model/TransactionDraft' -import { TransactionLinkDraft } from './model/TransactionLinkDraft' import { TransactionResult } from './model/TransactionResult' -import { UserAccountDraft } from './model/UserAccountDraft' const sendTransaction = gql` mutation ($input: TransactionDraft!) { @@ -30,40 +24,6 @@ const sendTransaction = gql` } ` -const deferredTransfer = gql` - mutation ($input: TransactionLinkDraft!) { - deferredTransfer(data: $input) { - error { - message - name - } - succeed - recipe { - createdAt - type - messageIdHex - } - } - } -` - -const registerAddress = gql` - mutation ($input: UserAccountDraft!) { - registerAddress(data: $input) { - error { - message - name - } - succeed - recipe { - createdAt - type - messageIdHex - } - } - } -` - // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts /** @@ -116,75 +76,17 @@ export class DltConnectorClient { return DltConnectorClient.instance } - private handleTransactionResult(result: TransactionResult) { - if (result.error) { - throw new Error(result.error.message) - } - return result - } - - private async sendTransaction(input: TransactionDraft) { + /** + * transmit transaction via dlt-connector to iota + * and update dltTransactionId of transaction in db with iota message id + */ + public async sendTransaction(input: TransactionDraft): Promise { + logger.debug('transmit transaction or user to dlt connector', input) const { data: { sendTransaction: result }, } = await this.client.rawRequest<{ sendTransaction: TransactionResult }>(sendTransaction, { input, }) - return this.handleTransactionResult(result) - } - - private async deferredTransfer(input: TransactionLinkDraft) { - const { - data: { deferredTransfer: result }, - } = await this.client.rawRequest<{ deferredTransfer: TransactionResult }>(deferredTransfer, { - input, - }) - return this.handleTransactionResult(result) - } - - private async registerAddress(input: UserAccountDraft) { - const { - data: { registerAddress: result }, - } = await this.client.rawRequest<{ registerAddress: TransactionResult }>(registerAddress, { - input, - }) - return this.handleTransactionResult(result) - } - - /** - * transmit transaction via dlt-connector to iota - * and update dltTransactionId of transaction in db with iota message id - */ - public async transmitTransaction( - input: TransactionDraft | UserAccountDraft | TransactionLinkDraft, - ): Promise { - // we don't need the receive transactions, there contain basically the same data as the send transactions - if ( - input instanceof TransactionDraft && - TransactionTypeId[input.type as keyof typeof TransactionTypeId] === TransactionTypeId.RECEIVE - ) { - return - } - - try { - logger.debug('transmit transaction or user to dlt connector', input) - if (input instanceof TransactionDraft) { - return await this.sendTransaction(input) - } else if (input instanceof UserAccountDraft) { - return await this.registerAddress(input) - } else if (input instanceof TransactionLinkDraft) { - return await this.deferredTransfer(input) - } else { - throw new LogError('unhandled branch reached') - } - } catch (e) { - logger.error(e) - if (e instanceof FetchError) { - throw e - } else if (e instanceof Error) { - throw new LogError(`from dlt-connector: ${e.message}`) - } else { - throw new LogError('Exception sending transfer transaction to dlt-connector', e) - } - } + return result } } diff --git a/backend/src/apis/dltConnector/enum/TransactionType.ts b/backend/src/apis/dltConnector/enum/TransactionType.ts index 51b87c134..095f56c47 100644 --- a/backend/src/apis/dltConnector/enum/TransactionType.ts +++ b/backend/src/apis/dltConnector/enum/TransactionType.ts @@ -1,11 +1,18 @@ +import { registerEnumType } from 'type-graphql' + /** * Transaction Types on Blockchain */ export enum TransactionType { - GRADIDO_TRANSFER = 1, - GRADIDO_CREATION = 2, - GROUP_FRIENDS_UPDATE = 3, - REGISTER_ADDRESS = 4, - GRADIDO_DEFERRED_TRANSFER = 5, - COMMUNITY_ROOT = 6, + GRADIDO_TRANSFER = 'GRADIDO_TRANSFER', + GRADIDO_CREATION = 'GRADIDO_CREATION', + GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', + REGISTER_ADDRESS = 'REGISTER_ADDRESS', + GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', + COMMUNITY_ROOT = 'COMMUNITY_ROOT', } + +registerEnumType(TransactionType, { + name: 'TransactionType', // this one is mandatory + description: 'Type of the transaction', // this one is optional +}) diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts index c1a73edd0..e21b853e6 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -3,8 +3,6 @@ import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from '@dbTools/ty import { DltTransaction } from '@entity/DltTransaction' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft' -import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' import { backendLogger as logger } from '@/server/logger' @@ -14,10 +12,7 @@ export abstract class AbstractTransactionToDltRole { // public interface public abstract initWithLast(): Promise public abstract getTimestamp(): number - public abstract convertToGraphqlInput(): - | TransactionDraft - | UserAccountDraft - | TransactionLinkDraft + public abstract convertToGraphqlInput(): TransactionDraft public getEntity(): T | null { return this.self @@ -48,7 +43,7 @@ export abstract class AbstractTransactionToDltRole { qb: SelectQueryBuilder, joinCondition: string, orderBy: OrderByCondition, - ): Promise { + ): SelectQueryBuilder { return qb .leftJoin(DltTransaction, 'dltTransaction', joinCondition) .where('dltTransaction.user_id IS NULL') @@ -56,7 +51,6 @@ export abstract class AbstractTransactionToDltRole { .andWhere('dltTransaction.transaction_link_Id IS NULL') .orderBy(orderBy) .limit(1) - .getOne() } protected createDltTransactionEntry(messageId: string, error: string | null): DltTransaction { diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 5b1efdad6..8aeccfa91 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -1,9 +1,11 @@ import { DltTransaction } from '@entity/DltTransaction' import { TransactionLink } from '@entity/TransactionLink' +import { TransactionType } from '@dltConnector/enum/TransactionType' +import { CommunityUser } from '@dltConnector/model/CommunityUser' +import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft' -import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft' +import { UserIdentifier } from '@dltConnector/model/UserIdentifier' import { LogError } from '@/server/LogError' @@ -19,7 +21,7 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { async initWithLast(): Promise { this.self = await this.createQueryForPendingItems( - Transaction.createQueryBuilder(), + Transaction.createQueryBuilder().leftJoinAndSelect( + 'Transaction.transactionLink', + 'transactionLink', + ), 'Transaction.id = dltTransaction.transactionId', // eslint-disable-next-line camelcase { balance_date: 'ASC', Transaction_id: 'ASC' }, ) + // we don't need the receive transactions, there contain basically the same data as the send transactions + .andWhere('transaction.typeId NOT :typeId', { typeId: TransactionTypeId.RECEIVE }) + .getOne() return this } @@ -30,11 +39,53 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole { 'User.id = dltTransaction.userId', // eslint-disable-next-line camelcase { User_created_at: 'ASC', User_id: 'ASC' }, - ) + ).getOne() return this } @@ -30,11 +32,16 @@ export class UserToDltRole extends AbstractTransactionToDltRole { return this.self.createdAt.getTime() } - public convertToGraphqlInput(): TransactionDraft | UserAccountDraft | TransactionLinkDraft { + public convertToGraphqlInput(): TransactionDraft { if (!this.self) { throw new LogError('try to create dlt entry for empty transaction') } - return new UserAccountDraft(this.self) + const draft = new TransactionDraft() + draft.user = new UserIdentifier(this.self.communityUuid, new CommunityUser(this.self.gradidoID)) + draft.createdAt = this.self.createdAt.toISOString() + draft.accountType = AccountType.COMMUNITY_HUMAN + draft.type = TransactionType.REGISTER_ADDRESS + return draft } protected setJoinId(dltTransaction: DltTransaction): void { diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts index 9e56eee81..7bf271cd0 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -1,12 +1,9 @@ -import { EntityPropertyNotFoundError, QueryFailedError, TypeORMError } from '@dbTools/typeorm' import { Transaction } from '@entity/Transaction' import { TransactionLink } from '@entity/TransactionLink' import { User } from '@entity/User' -// eslint-disable-next-line import/named, n/no-extraneous-import -import { FetchError } from 'node-fetch' import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' -import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' +import { backendLogger as logger } from '@/server/logger' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' @@ -40,21 +37,17 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis if (!pendingTransaction) { break } - let result: TransactionResult | undefined let messageId = '' let error: string | null = null - try { - result = await dltConnector.transmitTransaction( - pendingTransactionRole.convertToGraphqlInput(), - ) - if (result?.succeed && result.recipe) { - messageId = result.recipe.messageIdHex - } else { - error = 'skipped' - } - } catch (e) { - error = e instanceof Error ? e.message : String(e) + const result = await dltConnector.sendTransaction( + pendingTransactionRole.convertToGraphqlInput(), + ) + if (result?.succeed && result.recipe) { + messageId = result.recipe.messageIdHex + } else if (result?.error) { + error = result.error.message + logger.error('error from dlt-connector', result.error) } await pendingTransactionRole.saveTransactionResult(messageId, error) diff --git a/backend/src/apis/dltConnector/model/CommunityUser.ts b/backend/src/apis/dltConnector/model/CommunityUser.ts new file mode 100644 index 000000000..0a4eadebf --- /dev/null +++ b/backend/src/apis/dltConnector/model/CommunityUser.ts @@ -0,0 +1,10 @@ +export class CommunityUser { + // for community user, uuid and communityUuid used + uuid: string + accountNr?: number + + constructor(uuid: string, accountNr?: number) { + this.uuid = uuid + this.accountNr = accountNr + } +} diff --git a/backend/src/apis/dltConnector/model/IdentifierSeed.ts b/backend/src/apis/dltConnector/model/IdentifierSeed.ts new file mode 100644 index 000000000..7f7e2fe34 --- /dev/null +++ b/backend/src/apis/dltConnector/model/IdentifierSeed.ts @@ -0,0 +1,9 @@ +// https://www.npmjs.com/package/@apollo/protobufjs + +export class IdentifierSeed { + seed: string + + constructor(seed: string) { + this.seed = seed + } +} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index e31003986..8a2d7bdd5 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -1,39 +1,21 @@ // https://www.npmjs.com/package/@apollo/protobufjs -import { Transaction } from '@entity/Transaction' - -import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' -import { LogError } from '@/server/LogError' +import { AccountType } from '@dltConnector/enum/AccountType' +import { TransactionType } from '@dltConnector/enum/TransactionType' import { UserIdentifier } from './UserIdentifier' export class TransactionDraft { user: UserIdentifier - linkedUser: UserIdentifier - amount: string - type: string + // not used for simply register address + linkedUser?: UserIdentifier + // not used for register address + amount?: string + type: TransactionType createdAt: string - // only for creation transactions + // only for creation transaction targetDate?: string - - constructor(transaction: Transaction) { - this.amount = transaction.amount.abs().toString() - - if ( - !transaction.linkedUserGradidoID || - !transaction.linkedUserCommunityUuid || - !transaction.userCommunityUuid - ) { - throw new LogError( - `missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, - ) - } - this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid) - this.linkedUser = new UserIdentifier( - transaction.linkedUserGradidoID, - transaction.linkedUserCommunityUuid, - ) - this.createdAt = transaction.balanceDate.toISOString() - this.targetDate = transaction.creationDate?.toISOString() - this.type = TransactionTypeId[transaction.typeId] - } + // only for deferred transaction + timeoutDate?: string + // only for register address + accountType?: AccountType } diff --git a/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts b/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts deleted file mode 100644 index 1a12f552b..000000000 --- a/backend/src/apis/dltConnector/model/TransactionLinkDraft.ts +++ /dev/null @@ -1,21 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs -import { TransactionLink } from '@entity/TransactionLink' - -import { UserIdentifier } from './UserIdentifier' - -export class TransactionLinkDraft { - user: UserIdentifier - seed: string - amount: string - createdAt: string - timeoutDate: string - - constructor(transaction: TransactionLink) { - this.amount = transaction.amount.abs().toString() - const user = transaction.user - this.user = new UserIdentifier(user.gradidoID, user.communityUuid) - this.seed = transaction.code - this.createdAt = transaction.createdAt.toISOString() - this.timeoutDate = transaction.validUntil.toISOString() - } -} diff --git a/backend/src/apis/dltConnector/model/UserAccountDraft.ts b/backend/src/apis/dltConnector/model/UserAccountDraft.ts deleted file mode 100644 index dc52065d1..000000000 --- a/backend/src/apis/dltConnector/model/UserAccountDraft.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { User } from '@entity/User' - -import { AccountType } from '@/apis/dltConnector/enum/AccountType' - -import { UserIdentifier } from './UserIdentifier' - -export class UserAccountDraft { - user: UserIdentifier - createdAt: string - accountType: AccountType - - constructor(user: User) { - this.user = new UserIdentifier(user.gradidoID, user.communityUuid) - this.createdAt = user.createdAt.toISOString() - this.accountType = AccountType.COMMUNITY_HUMAN - } -} diff --git a/backend/src/apis/dltConnector/model/UserIdentifier.ts b/backend/src/apis/dltConnector/model/UserIdentifier.ts index 1824d17f3..059405bd0 100644 --- a/backend/src/apis/dltConnector/model/UserIdentifier.ts +++ b/backend/src/apis/dltConnector/model/UserIdentifier.ts @@ -1,11 +1,17 @@ -export class UserIdentifier { - uuid: string - communityUuid: string - accountNr?: number +import { CommunityUser } from './CommunityUser' +import { IdentifierSeed } from './IdentifierSeed' - constructor(uuid: string, communityUuid: string, accountNr?: number) { - this.uuid = uuid +export class UserIdentifier { + communityUuid: string + communityUser?: CommunityUser + seed?: IdentifierSeed // used for deferred transfers + + constructor(communityUuid: string, input: CommunityUser | IdentifierSeed) { + if (input instanceof CommunityUser) { + this.communityUser = input + } else if (input instanceof IdentifierSeed) { + this.seed = input + } this.communityUuid = communityUuid - this.accountNr = accountNr } } diff --git a/database/entity/0088-merge_dlt_tables/Transaction.ts b/database/entity/0088-merge_dlt_tables/Transaction.ts new file mode 100644 index 000000000..d5abed738 --- /dev/null +++ b/database/entity/0088-merge_dlt_tables/Transaction.ts @@ -0,0 +1,176 @@ +/* eslint-disable no-use-before-define */ +import { Decimal } from 'decimal.js-light' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + OneToOne, + JoinColumn, + ManyToOne, +} from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { Contribution } from '../Contribution' +import { DltTransaction } from '../DltTransaction' +import { TransactionLink } from '../TransactionLink' + +@Entity('transactions') +export class Transaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ type: 'int', unsigned: true, unique: true, nullable: true, default: null }) + previous: number | null + + @Column({ name: 'type_id', unsigned: true, nullable: false }) + typeId: number + + @Column({ + name: 'transaction_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + transactionLinkId?: number | null + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + amount: Decimal + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + balance: Decimal + + @Column({ + name: 'balance_date', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP', + nullable: false, + }) + balanceDate: Date + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + decay: Decimal + + @Column({ + name: 'decay_start', + type: 'datetime', + nullable: true, + default: null, + }) + decayStart: Date | null + + @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) + memo: string + + @Column({ name: 'creation_date', type: 'datetime', nullable: true, default: null }) + creationDate: Date | null + + @Column({ name: 'user_id', unsigned: true, nullable: false }) + userId: number + + @Column({ + name: 'user_community_uuid', + type: 'varchar', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + userCommunityUuid: string | null + + @Column({ + name: 'user_gradido_id', + type: 'varchar', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + userGradidoID: string + + @Column({ + name: 'user_name', + type: 'varchar', + length: 512, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + userName: string | null + + @Column({ + name: 'linked_user_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedUserId?: number | null + + @Column({ + name: 'linked_user_community_uuid', + type: 'varchar', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + linkedUserCommunityUuid: string | null + + @Column({ + name: 'linked_user_gradido_id', + type: 'varchar', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + linkedUserGradidoID: string | null + + @Column({ + name: 'linked_user_name', + type: 'varchar', + length: 512, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + linkedUserName: string | null + + @Column({ + name: 'linked_transaction_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + linkedTransactionId?: number | null + + @OneToOne(() => Contribution, (contribution) => contribution.transaction) + @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) + contribution?: Contribution | null + + @OneToOne(() => DltTransaction, (dlt) => dlt.transactionId) + @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) + dltTransaction?: DltTransaction | null + + @OneToOne(() => Transaction) + @JoinColumn({ name: 'previous' }) + previousTransaction?: Transaction | null + + @ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions) + @JoinColumn({ name: 'transactionLinkId' }) + transactionLink?: TransactionLink | null +} diff --git a/database/entity/0088-merge_dlt_tables/TransactionLink.ts b/database/entity/0088-merge_dlt_tables/TransactionLink.ts index 72c80195b..937544bd9 100644 --- a/database/entity/0088-merge_dlt_tables/TransactionLink.ts +++ b/database/entity/0088-merge_dlt_tables/TransactionLink.ts @@ -7,10 +7,12 @@ import { DeleteDateColumn, OneToOne, JoinColumn, + OneToMany, } from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { DltTransaction } from '../DltTransaction' import { User } from '../User' +import { Transaction } from '../Transaction' @Entity('transaction_links') export class TransactionLink extends BaseEntity { @@ -76,4 +78,8 @@ export class TransactionLink extends BaseEntity { @OneToOne(() => User, (user) => user.transactionLink) @JoinColumn({ name: 'userId' }) user: User + + @OneToMany(() => Transaction, (transaction) => transaction.transactionLink) + @JoinColumn({ referencedColumnName: 'transactionLinkId' }) + transactions: Transaction[] } diff --git a/database/entity/Transaction.ts b/database/entity/Transaction.ts index d1d7075a9..7b014e17a 100644 --- a/database/entity/Transaction.ts +++ b/database/entity/Transaction.ts @@ -1 +1 @@ -export { Transaction } from './0072-add_communityuuid_to_transactions_table/Transaction' +export { Transaction } from './0088-merge_dlt_tables/Transaction' diff --git a/database/logging/TransactionLinkLogging.view.ts b/database/logging/TransactionLinkLogging.view.ts new file mode 100644 index 000000000..781916131 --- /dev/null +++ b/database/logging/TransactionLinkLogging.view.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-unused-vars */ +import { TransactionLink } from '../entity/TransactionLink' +import { AbstractLoggingView } from './AbstractLogging.view' +import { DltTransactionLoggingView } from './DltTransactionLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class TransactionLinkLoggingView extends AbstractLoggingView { + public constructor(private self: TransactionLink) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + userId: this.self.userId, + amount: this.decimalToString(this.self.amount), + holdAvailableAmount: this.decimalToString(this.self.holdAvailableAmount), + memoLength: this.self.memo.length, + createdAt: this.dateToString(this.self.createdAt), + deletedAt: this.dateToString(this.self.deletedAt), + validUntil: this.dateToString(this.self.validUntil), + redeemedAt: this.dateToString(this.self.redeemedAt), + redeemedBy: this.self.redeemedBy, + dltTransaction: this.self.dltTransaction + ? new DltTransactionLoggingView(this.self.dltTransaction).toJSON() + : undefined, + user: this.self.user ? new UserLoggingView(this.self.user).toJSON() : undefined, + transactions: this.self.transactions.forEach( + (transaction) => new TransactionLoggingView(transaction), + ), + } + } +} diff --git a/database/logging/TransactionLogging.view.ts b/database/logging/TransactionLogging.view.ts index 7912c7e5d..fff2b46cb 100644 --- a/database/logging/TransactionLogging.view.ts +++ b/database/logging/TransactionLogging.view.ts @@ -1,8 +1,10 @@ /* eslint-disable no-unused-vars */ +import { LargeNumberLike } from 'crypto' import { Transaction } from '../entity/Transaction' import { AbstractLoggingView } from './AbstractLogging.view' import { ContributionLoggingView } from './ContributionLogging.view' import { DltTransactionLoggingView } from './DltTransactionLogging.view' +import { TransactionLinkLoggingView } from './TransactionLinkLogging.view' // TODO: move enum into database, maybe rename database enum TransactionTypeId { @@ -43,7 +45,7 @@ export class TransactionLoggingView extends AbstractLoggingView { linkedUserName: this.self.linkedUserName?.substring(0, 3) + '...', linkedTransactionId: this.self.linkedTransactionId, contribution: this.self.contribution - ? new ContributionLoggingView(this.self.contribution) + ? new ContributionLoggingView(this.self.contribution).toJSON() : undefined, dltTransaction: this.self.dltTransaction ? new DltTransactionLoggingView(this.self.dltTransaction).toJSON() @@ -51,6 +53,9 @@ export class TransactionLoggingView extends AbstractLoggingView { previousTransaction: this.self.previousTransaction ? new TransactionLoggingView(this.self.previousTransaction).toJSON() : undefined, + transactionLink: this.self.transactionLink + ? new TransactionLinkLoggingView(this.self.transactionLink).toJSON() + : undefined, } } } diff --git a/dlt-connector/src/graphql/enum/InputTransactionType.ts b/dlt-connector/src/graphql/enum/InputTransactionType.ts index 94cd39ff3..20e5e40f9 100755 --- a/dlt-connector/src/graphql/enum/InputTransactionType.ts +++ b/dlt-connector/src/graphql/enum/InputTransactionType.ts @@ -3,12 +3,12 @@ import { registerEnumType } from 'type-graphql' // enum for graphql but with int because it is the same in backend // for transaction type from backend export enum InputTransactionType { - CREATION = 1, - SEND = 2, - RECEIVE = 3, - // This is a virtual property, never occurring on the database - DECAY = 4, - LINK_SUMMARY = 5, + GRADIDO_TRANSFER = 'GRADIDO_TRANSFER', + GRADIDO_CREATION = 'GRADIDO_CREATION', + GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', + REGISTER_ADDRESS = 'REGISTER_ADDRESS', + GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', + COMMUNITY_ROOT = 'COMMUNITY_ROOT', } registerEnumType(InputTransactionType, { diff --git a/dlt-connector/src/graphql/input/CommunityDraft.ts b/dlt-connector/src/graphql/input/CommunityDraft.ts index 665e10b75..0b26e68d0 100644 --- a/dlt-connector/src/graphql/input/CommunityDraft.ts +++ b/dlt-connector/src/graphql/input/CommunityDraft.ts @@ -1,10 +1,9 @@ // https://www.npmjs.com/package/@apollo/protobufjs +import { isValidDateString } from '@validator/DateString' import { IsBoolean, IsUUID } from 'class-validator' import { Field, InputType } from 'type-graphql' -import { isValidDateString } from '@validator/DateString' - @InputType() export class CommunityDraft { @Field(() => String) diff --git a/dlt-connector/src/graphql/input/CommunityUser.ts b/dlt-connector/src/graphql/input/CommunityUser.ts new file mode 100644 index 000000000..97eff7a76 --- /dev/null +++ b/dlt-connector/src/graphql/input/CommunityUser.ts @@ -0,0 +1,15 @@ +// https://www.npmjs.com/package/@apollo/protobufjs + +import { IsPositive, IsUUID } from 'class-validator' +import { Field, Int, InputType } from 'type-graphql' + +@InputType() +export class CommunityUser { + @Field(() => String) + @IsUUID('4') + uuid: string + + @Field(() => Int, { defaultValue: 1, nullable: true }) + @IsPositive() + accountNr?: number +} diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index d1fa48c3c..3b2099ab6 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -4,6 +4,8 @@ import { isValidDateString, isValidNumberString } from '@validator/DateString' import { IsEnum, IsObject, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' +import { AccountType } from '@/graphql/enum/AccountType' + import { UserIdentifier } from './UserIdentifier' @InputType() @@ -13,14 +15,16 @@ export class TransactionDraft { @ValidateNested() user: UserIdentifier - @Field(() => UserIdentifier) + // not used for simply register address + @Field(() => UserIdentifier, { nullable: true }) @IsObject() @ValidateNested() - linkedUser: UserIdentifier + linkedUser?: UserIdentifier - @Field(() => String) + // not used for register address + @Field(() => String, { nullable: true }) @isValidNumberString() - amount: string + amount?: string @Field(() => InputTransactionType) @IsEnum(InputTransactionType) @@ -34,4 +38,14 @@ export class TransactionDraft { @Field(() => String, { nullable: true }) @isValidDateString() targetDate?: string + + // only for deferred transaction + @Field(() => String, { nullable: true }) + @isValidDateString() + timeoutDate?: string + + // only for register address + @Field(() => AccountType, { nullable: true }) + @IsEnum(AccountType) + accountType?: AccountType } diff --git a/dlt-connector/src/graphql/input/TransactionLinkDraft.ts b/dlt-connector/src/graphql/input/TransactionLinkDraft.ts deleted file mode 100644 index 7ac621e35..000000000 --- a/dlt-connector/src/graphql/input/TransactionLinkDraft.ts +++ /dev/null @@ -1,30 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs -import { isValidDateString, isValidNumberString } from '@validator/DateString' -import { IsObject, IsString, ValidateNested } from 'class-validator' -import { InputType, Field } from 'type-graphql' - -import { UserIdentifier } from './UserIdentifier' - -@InputType() -export class TransactionLinkDraft { - @Field(() => UserIdentifier) - @IsObject() - @ValidateNested() - user: UserIdentifier - - @Field(() => String) - @IsString() - seed: string - - @Field(() => String) - @isValidNumberString() - amount: string - - @Field(() => String) - @isValidDateString() - createdAt: string - - @Field(() => String) - @isValidDateString() - timeoutDate: string -} diff --git a/dlt-connector/src/graphql/input/UserAccountDraft.ts b/dlt-connector/src/graphql/input/UserAccountDraft.ts deleted file mode 100644 index 9ae544e32..000000000 --- a/dlt-connector/src/graphql/input/UserAccountDraft.ts +++ /dev/null @@ -1,26 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { IsEnum, IsObject, ValidateNested } from 'class-validator' -import { InputType, Field } from 'type-graphql' - -import { isValidDateString } from '@validator/DateString' - -import { AccountType } from '@/graphql/enum/AccountType' - -import { UserIdentifier } from './UserIdentifier' - -@InputType() -export class UserAccountDraft { - @Field(() => UserIdentifier) - @IsObject() - @ValidateNested() - user: UserIdentifier - - @Field(() => String) - @isValidDateString() - createdAt: string - - @Field(() => AccountType) - @IsEnum(AccountType) - accountType: AccountType -} diff --git a/dlt-connector/src/graphql/input/UserIdentifier.ts b/dlt-connector/src/graphql/input/UserIdentifier.ts index 7d9035b93..f622c24e4 100644 --- a/dlt-connector/src/graphql/input/UserIdentifier.ts +++ b/dlt-connector/src/graphql/input/UserIdentifier.ts @@ -1,19 +1,24 @@ // https://www.npmjs.com/package/@apollo/protobufjs -import { IsPositive, IsUUID } from 'class-validator' -import { Field, Int, InputType } from 'type-graphql' +import { IsObject, IsUUID, ValidateNested } from 'class-validator' +import { Field, InputType } from 'type-graphql' + +import { CommunityUser } from './CommunityUser' +import { IdentifierSeed } from './IdentifierSeed' @InputType() export class UserIdentifier { - @Field(() => String) - @IsUUID('4') - uuid: string - @Field(() => String) @IsUUID('4') communityUuid: string - @Field(() => Int, { defaultValue: 1, nullable: true }) - @IsPositive() - accountNr?: number + @Field(() => CommunityUser, { nullable: true }) + @IsObject() + @ValidateNested() + communityUser?: CommunityUser + + @Field(() => IdentifierSeed, { nullable: true }) + @IsObject() + @ValidateNested() + seed?: IdentifierSeed } diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts index a7f264764..ab7203285 100644 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -1,15 +1,14 @@ /* eslint-disable camelcase */ import { AddressType_NONE } from 'gradido-blockchain-js' -import { Arg, Mutation, Query, Resolver } from 'type-graphql' +import { Arg, Query, Resolver } from 'type-graphql' import { getAddressType } from '@/client/GradidoNode' import { KeyPairCalculation } from '@/interactions/keyPairCalculation/KeyPairCalculation.context' -import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' import { logger } from '@/logging/logger' +import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' import { uuid4ToHash } from '@/utils/typeConverter' import { TransactionErrorType } from '../enum/TransactionErrorType' -import { UserAccountDraft } from '../input/UserAccountDraft' import { UserIdentifier } from '../input/UserIdentifier' import { TransactionError } from '../model/TransactionError' import { TransactionResult } from '../model/TransactionResult' @@ -25,6 +24,7 @@ export class AccountResolver { new TransactionError(TransactionErrorType.NOT_FOUND, 'cannot get user public key'), ) } + // ask gradido node server for account type, if type !== NONE account exist const addressType = await getAddressType( publicKey.data(), @@ -33,21 +33,4 @@ export class AccountResolver { logger.info('isAccountExist', userIdentifier) return addressType !== AddressType_NONE } - - @Mutation(() => TransactionResult) - async registerAddress( - @Arg('data') - userAccountDraft: UserAccountDraft, - ): Promise { - try { - return await SendToIotaContext(userAccountDraft) - } catch (err) { - if (err instanceof TransactionError) { - return new TransactionResult(err) - } else { - logger.error('error in register address: ', err) - throw err - } - } - } } diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts index 8d3d5970b..e7d1c105e 100755 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts @@ -1,4 +1,3 @@ -import { TransactionLinkDraft } from '@input/TransactionLinkDraft' import { Resolver, Arg, Mutation } from 'type-graphql' import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' @@ -25,21 +24,4 @@ export class TransactionResolver { } } } - - @Mutation(() => TransactionResult) - async deferredTransfer( - @Arg('data') - transactionLinkDraft: TransactionLinkDraft, - ): Promise { - try { - return await SendToIotaContext(transactionLinkDraft) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error instanceof TransactionError) { - return new TransactionResult(error) - } else { - throw error - } - } - } } diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index ca54d8d16..3cb1f43cf 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -15,9 +15,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' * @DCI-Context * Context for calculating key pair for signing transactions */ -export async function KeyPairCalculation( - input: UserIdentifier | string | IdentifierSeed, -): Promise { +export async function KeyPairCalculation(input: UserIdentifier | string): Promise { const cache = KeyPairCacheManager.getInstance() // Try cache lookup first @@ -26,11 +24,9 @@ export async function KeyPairCalculation( return keyPair } - const retrieveKeyPair = async ( - input: UserIdentifier | string | IdentifierSeed, - ): Promise => { - if (input instanceof IdentifierSeed) { - return new LinkedTransactionKeyPairRole(input.seed).generateKeyPair() + const retrieveKeyPair = async (input: UserIdentifier | string): Promise => { + if (input instanceof UserIdentifier && input.seed) { + return new LinkedTransactionKeyPairRole(input.seed.seed).generateKeyPair() } const communityUUID = input instanceof UserIdentifier ? input.communityUuid : input @@ -51,7 +47,7 @@ export async function KeyPairCalculation( } if (input instanceof UserIdentifier) { const userKeyPair = new UserKeyPairRole(input, communityKeyPair).generateKeyPair() - const accountNr = input.accountNr ?? 1 + const accountNr = input.communityUser?.accountNr ?? 1 return new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() } return communityKeyPair diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts index 1cc9c9891..132e86499 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -13,7 +13,11 @@ export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { } public async retrieveKeyPair(): Promise { - const nameHash = uuid4ToHash(this.user.uuid) + if (!this.user.communityUser) { + throw new LogError('missing community user') + } + + const nameHash = uuid4ToHash(this.user.communityUser.uuid) const confirmedTransactions = await getTransactions( 0, 30, diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts index 473b203cd..6f433a7df 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -1,6 +1,7 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { LogError } from '@/server/LogError' import { hardenDerivationIndex } from '@/utils/derivationHelper' import { uuid4ToBuffer } from '@/utils/typeConverter' @@ -14,7 +15,10 @@ export class UserKeyPairRole extends AbstractKeyPairRole { public generateKeyPair(): KeyPairEd25519 { // example gradido id: 03857ac1-9cc2-483e-8a91-e5b10f5b8d16 => // wholeHex: '03857ac19cc2483e8a91e5b10f5b8d16'] - const wholeHex = uuid4ToBuffer(this.user.uuid) + if (!this.user.communityUser) { + throw new LogError('missing community user') + } + const wholeHex = uuid4ToBuffer(this.user.communityUser.uuid) const parts = [] for (let i = 0; i < 4; i++) { parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index c448a1704..2865193a9 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -1,7 +1,8 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { LogError } from '@/server/LogError' +import { TransactionError } from '@/graphql/model/TransactionError' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -17,12 +18,27 @@ export class CreationTransactionRole extends AbstractTransactionRole { } getRecipientCommunityUuid(): string { - throw new LogError('cannot be used as cross group transaction') + throw new TransactionError( + TransactionErrorType.LOGIC_ERROR, + 'creation: cannot be used as cross group transaction', + ) } public async getGradidoTransactionBuilder(): Promise { if (!this.self.targetDate) { - throw new LogError('target date missing for creation transaction') + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'creation: target date missing', + ) + } + if (!this.self.linkedUser) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'creation: linked user missing', + ) + } + if (!this.self.amount) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'creation: amount missing') } const builder = new GradidoTransactionBuilder() const recipientKeyPair = await KeyPairCalculation(this.self.user) diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 7a4c627a1..511efa869 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,15 +1,15 @@ import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' -import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft' -import { LogError } from '@/server/LogError' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { TransactionError } from '@/graphql/model/TransactionError' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class DeferredTransferTransactionRole extends AbstractTransactionRole { - constructor(protected self: TransactionLinkDraft) { + constructor(protected self: TransactionDraft) { super() } @@ -18,13 +18,34 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { } getRecipientCommunityUuid(): string { - throw new LogError('cannot be used as cross group transaction') + throw new TransactionError( + TransactionErrorType.LOGIC_ERROR, + 'deferred transfer: cannot be used as cross group transaction', + ) } public async getGradidoTransactionBuilder(): Promise { + if (!this.self.linkedUser || !this.self.linkedUser.seed) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'deferred transfer: missing linked user or not a seed', + ) + } + if (!this.self.amount) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'deferred transfer: amount missing', + ) + } + if (!this.self.timeoutDate) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'deferred transfer: timeout date missing', + ) + } const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(new IdentifierSeed(this.self.seed)) + const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) builder .setCreatedAt(new Date(this.self.createdAt)) diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts index dc80d7c02..f8c82586d 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -1,7 +1,9 @@ /* eslint-disable camelcase */ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { TransactionError } from '@/graphql/model/TransactionError' import { LogError } from '@/server/LogError' import { accountTypeToAddressType, uuid4ToHash } from '@/utils/typeConverter' @@ -10,7 +12,7 @@ import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.con import { AbstractTransactionRole } from './AbstractTransaction.role' export class RegisterAddressTransactionRole extends AbstractTransactionRole { - constructor(private self: UserAccountDraft) { + constructor(private self: TransactionDraft) { super() } @@ -23,6 +25,20 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { } public async getGradidoTransactionBuilder(): Promise { + if (!this.self.accountType) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'register address: account type missing', + ) + } + + if (!this.self.user.communityUser) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + "register address: user isn't a community user", + ) + } + const builder = new GradidoTransactionBuilder() const communityKeyPair = await KeyPairCalculation(this.self.user.communityUuid) const accountKeyPair = await KeyPairCalculation(this.self.user) @@ -31,7 +47,7 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { .setRegisterAddress( accountKeyPair.getPublicKey(), accountTypeToAddressType(this.self.accountType), - uuid4ToHash(this.self.user.uuid), + uuid4ToHash(this.self.user.communityUser.uuid), ) .sign(communityKeyPair) .sign(accountKeyPair) diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index caf4df11f..be02eef55 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -12,8 +12,6 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft' -import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' import { TransactionError } from '@/graphql/model/TransactionError' import { TransactionRecipe } from '@/graphql/model/TransactionRecipe' import { TransactionResult } from '@/graphql/model/TransactionResult' @@ -34,7 +32,7 @@ import { TransferTransactionRole } from './TransferTransaction.role' * send every transaction only once to iota! */ export async function SendToIotaContext( - input: TransactionDraft | UserAccountDraft | CommunityDraft | TransactionLinkDraft, + input: TransactionDraft | CommunityDraft, ): Promise { const validate = (transaction: GradidoTransaction): void => { try { @@ -76,17 +74,25 @@ export async function SendToIotaContext( let role: AbstractTransactionRole if (input instanceof TransactionDraft) { - if (input.type === InputTransactionType.CREATION) { - role = new CreationTransactionRole(input) - } else if (input.type === InputTransactionType.SEND) { - role = new TransferTransactionRole(input) - } else { - throw new LogError('not supported transaction type') + switch (input.type) { + case InputTransactionType.GRADIDO_CREATION: + role = new CreationTransactionRole(input) + break + case InputTransactionType.GRADIDO_TRANSFER: + role = new TransferTransactionRole(input) + break + case InputTransactionType.REGISTER_ADDRESS: + role = new RegisterAddressTransactionRole(input) + break + case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: + role = new DeferredTransferTransactionRole(input) + break + default: + throw new TransactionError( + TransactionErrorType.NOT_IMPLEMENTED_YET, + 'not supported transaction type: ' + input.type, + ) } - } else if (input instanceof TransactionLinkDraft) { - role = new DeferredTransferTransactionRole(input) - } else if (input instanceof UserAccountDraft) { - role = new RegisterAddressTransactionRole(input) } else if (input instanceof CommunityDraft) { role = new CommunityRootTransactionRole(input) } else { diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index 1e5dde5dd..7a4cd7bb0 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -1,6 +1,9 @@ import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { TransactionError } from '@/graphql/model/TransactionError' import { uuid4ToHash } from '@/utils/typeConverter' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -8,8 +11,16 @@ import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.con import { AbstractTransactionRole } from './AbstractTransaction.role' export class TransferTransactionRole extends AbstractTransactionRole { - constructor(protected self: TransactionDraft) { + private linkedUser: UserIdentifier + constructor(private self: TransactionDraft) { super() + if (!this.self.linkedUser) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'transfer: linked user missing', + ) + } + this.linkedUser = this.self.linkedUser } getSenderCommunityUuid(): string { @@ -17,13 +28,16 @@ export class TransferTransactionRole extends AbstractTransactionRole { } getRecipientCommunityUuid(): string { - return this.self.linkedUser.communityUuid + return this.linkedUser.communityUuid } public async getGradidoTransactionBuilder(): Promise { + if (!this.self.amount) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'transfer: amount missing') + } const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + const recipientKeyPair = await KeyPairCalculation(this.linkedUser) builder .setCreatedAt(new Date(this.self.createdAt)) .setMemo('dummy memo for transfer') @@ -32,7 +46,7 @@ export class TransferTransactionRole extends AbstractTransactionRole { recipientKeyPair.getPublicKey(), ) const senderCommunity = this.self.user.communityUuid - const recipientCommunity = this.self.linkedUser.communityUuid + const recipientCommunity = this.linkedUser.communityUuid if (senderCommunity !== recipientCommunity) { // we have a cross group transaction builder diff --git a/dlt-connector/src/logging/CommunityUserLogging.view.ts b/dlt-connector/src/logging/CommunityUserLogging.view.ts new file mode 100644 index 000000000..f1b421cd6 --- /dev/null +++ b/dlt-connector/src/logging/CommunityUserLogging.view.ts @@ -0,0 +1,17 @@ +import { CommunityUser } from '@/graphql/input/CommunityUser' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class CommunityUserLoggingView extends AbstractLoggingView { + public constructor(private self: CommunityUser) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + uuid: this.self.uuid, + accountNr: this.self.accountNr, + } + } +} diff --git a/dlt-connector/src/logging/IdentifierSeedLogging.view.ts b/dlt-connector/src/logging/IdentifierSeedLogging.view.ts new file mode 100644 index 000000000..d34012e17 --- /dev/null +++ b/dlt-connector/src/logging/IdentifierSeedLogging.view.ts @@ -0,0 +1,16 @@ +import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class IdentifierSeedLoggingView extends AbstractLoggingView { + public constructor(private self: IdentifierSeed) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + seed: this.self.seed, + } + } +} diff --git a/dlt-connector/src/logging/UserIdentifierLogging.view.ts b/dlt-connector/src/logging/UserIdentifierLogging.view.ts index 54ac4b07d..16343551f 100644 --- a/dlt-connector/src/logging/UserIdentifierLogging.view.ts +++ b/dlt-connector/src/logging/UserIdentifierLogging.view.ts @@ -1,6 +1,8 @@ import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { AbstractLoggingView } from './AbstractLogging.view' +import { CommunityUserLoggingView } from './CommunityUserLogging.view' +import { IdentifierSeedLoggingView } from './IdentifierSeedLogging.view' export class UserIdentifierLoggingView extends AbstractLoggingView { public constructor(private self: UserIdentifier) { @@ -10,9 +12,11 @@ export class UserIdentifierLoggingView extends AbstractLoggingView { // eslint-disable-next-line @typescript-eslint/no-explicit-any public toJSON(): any { return { - uuid: this.self.uuid, communityUuid: this.self.communityUuid, - accountNr: this.self.accountNr, + communityUser: this.self.communityUser + ? new CommunityUserLoggingView(this.self.communityUser).toJSON() + : undefined, + seed: this.self.seed ? new IdentifierSeedLoggingView(this.self.seed).toJSON() : undefined, } } } diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/manager/KeyPairCacheManager.ts index 844f5ad58..5f5d94f41 100644 --- a/dlt-connector/src/manager/KeyPairCacheManager.ts +++ b/dlt-connector/src/manager/KeyPairCacheManager.ts @@ -45,14 +45,11 @@ export class KeyPairCacheManager { return this.homeCommunityUUID } - public findKeyPair(input: UserIdentifier | string | IdentifierSeed): KeyPairEd25519 | undefined { + public findKeyPair(input: UserIdentifier | string): KeyPairEd25519 | undefined { return this.cache.get(this.getKey(input)) } - public addKeyPair( - input: UserIdentifier | string | IdentifierSeed, - keyPair: KeyPairEd25519, - ): void { + public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void { const key = this.getKey(input) if (this.cache.has(key)) { throw new LogError('key already exist, cannot add', key) @@ -60,13 +57,17 @@ export class KeyPairCacheManager { this.cache.set(key, keyPair) } - protected getKey(input: UserIdentifier | string | IdentifierSeed): string { + protected getKey(input: UserIdentifier | string): string { if (input instanceof UserIdentifier) { - return input.uuid - } else if (input instanceof IdentifierSeed) { - return input.seed - } else { + if (input.communityUser) { + return input.communityUser.uuid + } else if (input.seed) { + return input.seed.seed + } + throw new LogError('unhandled branch') + } else if (typeof input === 'string') { return input } + throw new LogError('unhandled input type') } } From ec2d5cb98dcd95764a8c1afdad9b1e604a9b4f94 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 15 Nov 2024 19:58:50 +0100 Subject: [PATCH 020/226] handle deletiono of transaction link with dlt --- .../dltConnector/enum/DltTransactionType.ts | 8 ++ .../AbstractTransactionToDlt.role.ts | 5 +- .../TransactionLinkDeleteToDlt.role.ts | 83 +++++++++++++++++++ .../TransactionLinkToDlt.role.ts | 4 +- .../transactionToDlt/TransactionToDlt.role.ts | 32 ++++--- .../transactionToDlt/UserToDlt.role.ts | 4 +- .../transactionToDlt.context.ts | 2 + .../resolver/TransactionLinkResolver.ts | 8 ++ .../0088-merge_dlt_tables/DltTransaction.ts | 3 + .../0088-merge_dlt_tables/Transaction.ts | 2 +- .../0088-merge_dlt_tables/TransactionLink.ts | 2 +- database/migrations/0088-merge_dlt_tables.ts | 8 +- .../src/manager/KeyPairCacheManager.ts | 5 +- 13 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 backend/src/apis/dltConnector/enum/DltTransactionType.ts create mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts diff --git a/backend/src/apis/dltConnector/enum/DltTransactionType.ts b/backend/src/apis/dltConnector/enum/DltTransactionType.ts new file mode 100644 index 000000000..80e12daa5 --- /dev/null +++ b/backend/src/apis/dltConnector/enum/DltTransactionType.ts @@ -0,0 +1,8 @@ +export enum DltTransactionType { + REGISTER_ADDRESS = 1, + CREATION = 2, + TRANSFER = 3, + DEFERRED_TRANSFER = 4, + REDEEM_DEFERRED_TRANSFER = 5, + DELETE_DEFERRED_TRANSFER = 6, +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts index e21b853e6..ac77f4195 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -22,7 +22,7 @@ export abstract class AbstractTransactionToDltRole { const dltTransaction = DltTransaction.create() dltTransaction.messageId = messageId dltTransaction.error = error - this.setJoinId(dltTransaction) + this.setJoinIdAndType(dltTransaction) await DltTransaction.save(dltTransaction) if (dltTransaction.error) { logger.error( @@ -36,7 +36,7 @@ export abstract class AbstractTransactionToDltRole { } // intern - protected abstract setJoinId(dltTransaction: DltTransaction): void + protected abstract setJoinIdAndType(dltTransaction: DltTransaction): void // helper protected createQueryForPendingItems( @@ -50,7 +50,6 @@ export abstract class AbstractTransactionToDltRole { .andWhere('dltTransaction.transaction_id IS NULL') .andWhere('dltTransaction.transaction_link_Id IS NULL') .orderBy(orderBy) - .limit(1) } protected createDltTransactionEntry(messageId: string, error: string | null): DltTransaction { diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts new file mode 100644 index 000000000..742a0b96d --- /dev/null +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts @@ -0,0 +1,83 @@ +import { DltTransaction } from '@entity/DltTransaction' +import { TransactionLink } from '@entity/TransactionLink' + +import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' +import { TransactionType } from '@dltConnector/enum/TransactionType' +import { CommunityUser } from '@dltConnector/model/CommunityUser' +import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' +import { TransactionDraft } from '@dltConnector/model/TransactionDraft' +import { UserIdentifier } from '@dltConnector/model/UserIdentifier' + +import { LogError } from '@/server/LogError' + +import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' + +/** + * redeem deferred transfer transaction by creator, so "deleting" it + */ +export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole { + async initWithLast(): Promise { + const queryBuilder = this.createQueryForPendingItems( + TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'), + 'TransactionLink.id = dltTransaction.transactionLinkId and dltTransaction.type_id <> 4', + // eslint-disable-next-line camelcase + { TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }, + ) + .andWhere('TransactionLink.deletedAt IS NOT NULL') + .withDeleted() + const queryBuilder2 = TransactionLink.createQueryBuilder() + .leftJoinAndSelect('TransactionLink.user', 'user') + .where('TransactionLink.deletedAt IS NOT NULL') + .andWhere(() => { + const subQuery = DltTransaction.createQueryBuilder() + .select('1') + .where('DltTransaction.transaction_link_id = TransactionLink.id') + .andWhere('DltTransaction.type_id = :typeId', { + typeId: DltTransactionType.DELETE_DEFERRED_TRANSFER, + }) + .getQuery() + return `NOT EXIST (${subQuery})` + }) + .withDeleted() + // eslint-disable-next-line camelcase + .orderBy({ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }) + // console.log('query: ', queryBuilder.getSql()) + this.self = await queryBuilder.getOne() + return this + } + + public getTimestamp(): number { + if (!this.self) { + return Infinity + } + if (!this.self.deletedAt) { + throw new LogError('not deleted transaction link selected') + } + return this.self.deletedAt.getTime() + } + + public convertToGraphqlInput(): TransactionDraft { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction link') + } + if (!this.self.deletedAt) { + throw new LogError('not deleted transaction link selected') + } + const draft = new TransactionDraft() + draft.amount = this.self.amount.abs().toString() + const user = this.self.user + draft.user = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code)) + draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID)) + draft.createdAt = this.self.deletedAt.toISOString() + draft.type = TransactionType.GRADIDO_TRANSFER + return draft + } + + protected setJoinIdAndType(dltTransaction: DltTransaction): void { + if (!this.self) { + throw new LogError('try to create dlt entry for empty transaction link') + } + dltTransaction.transactionLinkId = this.self.id + dltTransaction.typeId = DltTransactionType.DELETE_DEFERRED_TRANSFER + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 8aeccfa91..916aacbfc 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -1,6 +1,7 @@ import { DltTransaction } from '@entity/DltTransaction' import { TransactionLink } from '@entity/TransactionLink' +import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' import { CommunityUser } from '@dltConnector/model/CommunityUser' import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' @@ -47,10 +48,11 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { + private type: DltTransactionType async initWithLast(): Promise { this.self = await this.createQueryForPendingItems( Transaction.createQueryBuilder().leftJoinAndSelect( @@ -27,7 +29,7 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole :typeId', { typeId: TransactionTypeId.RECEIVE }) .getOne() return this } @@ -55,6 +57,19 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole { return draft } - protected setJoinId(dltTransaction: DltTransaction): void { + protected setJoinIdAndType(dltTransaction: DltTransaction): void { if (!this.self) { throw new LogError('try to create dlt entry for empty user') } dltTransaction.userId = this.self.id + dltTransaction.typeId = DltTransactionType.REGISTER_ADDRESS } } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts index 7bf271cd0..bd49c8400 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -6,6 +6,7 @@ import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' import { backendLogger as logger } from '@/server/logger' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' +import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role' import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' import { TransactionToDltRole } from './TransactionToDlt.role' import { UserToDltRole } from './UserToDlt.role' @@ -23,6 +24,7 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis new TransactionToDltRole().initWithLast(), new UserToDltRole().initWithLast(), new TransactionLinkToDltRole().initWithLast(), + new TransactionLinkDeleteToDltRole().initWithLast(), ]) // sort array to get oldest at first place diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 88f84b6e2..68bcd5f09 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -33,6 +33,10 @@ import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { calculateDecay } from '@/util/decay' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' import { TRANSACTION_LINK_LOCK } from '@/util/TRANSACTION_LINK_LOCK' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' @@ -300,6 +304,8 @@ export class TransactionLinkResolver { contributionLink, contributionLink.amount, ) + // notify dlt-connector loop for new work + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Creation from contribution link was not successful', e) @@ -354,6 +360,8 @@ export class TransactionLinkResolver { transactionLink, transactionLink.amount, ) + // notify dlt-connector loop for new work + InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) } finally { releaseLinkLock() } diff --git a/database/entity/0088-merge_dlt_tables/DltTransaction.ts b/database/entity/0088-merge_dlt_tables/DltTransaction.ts index 6525c229d..012bddf0b 100644 --- a/database/entity/0088-merge_dlt_tables/DltTransaction.ts +++ b/database/entity/0088-merge_dlt_tables/DltTransaction.ts @@ -17,6 +17,9 @@ export class DltTransaction extends BaseEntity { @Column({ name: 'transaction_link_id', type: 'int', unsigned: true, nullable: true }) transactionLinkId?: number | null + @Column({ name: 'type_id', unsigned: true, nullable: false }) + typeId: number + @Column({ name: 'message_id', length: 64, diff --git a/database/entity/0088-merge_dlt_tables/Transaction.ts b/database/entity/0088-merge_dlt_tables/Transaction.ts index d5abed738..8eec4e1a9 100644 --- a/database/entity/0088-merge_dlt_tables/Transaction.ts +++ b/database/entity/0088-merge_dlt_tables/Transaction.ts @@ -171,6 +171,6 @@ export class Transaction extends BaseEntity { previousTransaction?: Transaction | null @ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions) - @JoinColumn({ name: 'transactionLinkId' }) + @JoinColumn({ name: 'transaction_link_id' }) transactionLink?: TransactionLink | null } diff --git a/database/entity/0088-merge_dlt_tables/TransactionLink.ts b/database/entity/0088-merge_dlt_tables/TransactionLink.ts index 937544bd9..18bcf9892 100644 --- a/database/entity/0088-merge_dlt_tables/TransactionLink.ts +++ b/database/entity/0088-merge_dlt_tables/TransactionLink.ts @@ -80,6 +80,6 @@ export class TransactionLink extends BaseEntity { user: User @OneToMany(() => Transaction, (transaction) => transaction.transactionLink) - @JoinColumn({ referencedColumnName: 'transactionLinkId' }) + @JoinColumn({ referencedColumnName: 'transaction_link_id' }) transactions: Transaction[] } diff --git a/database/migrations/0088-merge_dlt_tables.ts b/database/migrations/0088-merge_dlt_tables.ts index 7964ffd94..ab3db11eb 100644 --- a/database/migrations/0088-merge_dlt_tables.ts +++ b/database/migrations/0088-merge_dlt_tables.ts @@ -7,7 +7,9 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ALTER TABLE \`dlt_transactions\` CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL, ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, - ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`; + ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\` + ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\` + ; `) } @@ -28,6 +30,8 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom ALTER TABLE \`dlt_transactions\` CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NOT NULL, DROP COLUMN \`user_id\`, - DROP COLUMN \`transaction_link_id\`; + DROP COLUMN \`transaction_link_id\` + DROP COLUMN \`type_id\` + ; `) } diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/manager/KeyPairCacheManager.ts index 5f5d94f41..f492d127b 100644 --- a/dlt-connector/src/manager/KeyPairCacheManager.ts +++ b/dlt-connector/src/manager/KeyPairCacheManager.ts @@ -1,7 +1,7 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example @@ -52,7 +52,8 @@ export class KeyPairCacheManager { public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void { const key = this.getKey(input) if (this.cache.has(key)) { - throw new LogError('key already exist, cannot add', key) + logger.warn('key already exist, cannot add', key) + return } this.cache.set(key, keyPair) } From eb424fc6c5e56ede3f6f1bfc2a056ecff9e51372 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 10 Jan 2025 20:27:59 +0100 Subject: [PATCH 021/226] refactor for deferred transfer --- .../dltConnector/DltConnectorClient.test.ts | 2 - .../apis/dltConnector/enum/TransactionType.ts | 1 + .../TransactionLinkDeleteToDlt.role.ts | 6 +- .../TransactionLinkToDlt.role.ts | 5 +- .../transactionToDlt/TransactionToDlt.role.ts | 5 +- .../dltConnector/model/TransactionDraft.ts | 3 +- dlt-connector/package.json | 2 +- dlt-connector/src/client/GradidoNode.ts | 36 +++++- dlt-connector/src/data/KeyPairIdentifier.ts | 72 ++++++++++++ dlt-connector/src/graphql/const.ts | 2 + .../src/graphql/enum/InputTransactionType.ts | 1 + .../src/graphql/enum/TransactionErrorType.ts | 1 + .../src/graphql/input/TransactionDraft.ts | 15 ++- .../src/graphql/resolver/AccountsResolver.ts | 4 +- .../ForeignCommunityKeyPair.role.ts | 2 +- .../KeyPairCalculation.context.ts | 51 ++++++--- .../keyPairCalculation/UserKeyPair.role.ts | 10 +- .../CommunityRootTransaction.role.ts | 3 +- .../sendToIota/CreationTransaction.role.ts | 28 ++++- .../DeferredTransferTransaction.role.ts | 41 +++++-- .../RedeemDeferredTransferTransaction.role.ts | 103 ++++++++++++++++++ .../RegisterAddressTransaction.role.ts | 15 ++- .../sendToIota/SendToIota.context.ts | 15 +-- .../sendToIota/TransferTransaction.role.ts | 30 ++++- .../src/manager/KeyPairCacheManager.ts | 30 ++--- dlt-connector/src/utils/typeConverter.ts | 12 ++ dlt-connector/yarn.lock | 4 +- 27 files changed, 403 insertions(+), 96 deletions(-) create mode 100644 dlt-connector/src/data/KeyPairIdentifier.ts create mode 100644 dlt-connector/src/graphql/const.ts create mode 100644 dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index 5cd7c3269..28c1c969c 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -10,11 +10,9 @@ import { Decimal } from 'decimal.js-light' import { cleanDB, testEnvironment } from '@test/helpers' import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { DltConnectorClient } from './DltConnectorClient' -import { TransactionDraft } from './model/TransactionDraft' let con: Connection diff --git a/backend/src/apis/dltConnector/enum/TransactionType.ts b/backend/src/apis/dltConnector/enum/TransactionType.ts index 095f56c47..d12bb3fa2 100644 --- a/backend/src/apis/dltConnector/enum/TransactionType.ts +++ b/backend/src/apis/dltConnector/enum/TransactionType.ts @@ -9,6 +9,7 @@ export enum TransactionType { GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', REGISTER_ADDRESS = 'REGISTER_ADDRESS', GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', + GRADIDO_REDEEM_DEFERRED_TRANSFER = 'GRADIDO_REDEEM_DEFERRED_TRANSFER', COMMUNITY_ROOT = 'COMMUNITY_ROOT', } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts index 742a0b96d..b761b71c6 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts @@ -25,6 +25,7 @@ export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole ) .andWhere('TransactionLink.deletedAt IS NOT NULL') .withDeleted() + /* const queryBuilder2 = TransactionLink.createQueryBuilder() .leftJoinAndSelect('TransactionLink.user', 'user') .where('TransactionLink.deletedAt IS NOT NULL') @@ -41,6 +42,7 @@ export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole .withDeleted() // eslint-disable-next-line camelcase .orderBy({ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }) + */ // console.log('query: ', queryBuilder.getSql()) this.self = await queryBuilder.getOne() return this @@ -67,9 +69,9 @@ export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole draft.amount = this.self.amount.abs().toString() const user = this.self.user draft.user = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code)) - draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID)) + draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID, 1)) draft.createdAt = this.self.deletedAt.toISOString() - draft.type = TransactionType.GRADIDO_TRANSFER + draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER return draft } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 916aacbfc..16ba7f6f8 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -40,10 +40,11 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { + const parameter = { + pubkey: pubkey.convertToHex(), + format: 'base64', + firstTransactionNr, + maxResultCount, + communityId: iotaTopic, + } + logger.info('call listtransactionsforaddress on Node Server via jsonrpc 2.0', parameter) + const response = await client.exec( + 'listtransactionsforaddress', + parameter, + ) + return resolveResponse(response, (result: ConfirmedTransactionList) => { + logger.debug('GradidoNode used time', result.timeUsed) + return result.transactions.map((transactionBase64) => + confirmedTransactionFromBase64(transactionBase64), + ) + }) +} + +export { + getTransaction, + getLastTransaction, + getTransactions, + getAddressType, + getTransactionsForAccount, +} diff --git a/dlt-connector/src/data/KeyPairIdentifier.ts b/dlt-connector/src/data/KeyPairIdentifier.ts new file mode 100644 index 000000000..3a98c2e0e --- /dev/null +++ b/dlt-connector/src/data/KeyPairIdentifier.ts @@ -0,0 +1,72 @@ +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { LogError } from '@/server/LogError' +import { uuid4sToMemoryBlock } from '@/utils/typeConverter' + +export class KeyPairIdentifier { + // used for community key pair if it is only parameter or for user key pair + communityUuid?: string + // if set calculate key pair from seed, ignore all other parameter + seed?: string + // used for user key pair and account key pair, need also communityUuid + userUuid?: string + // used for account key pair, need also userUuid + accountNr?: number + + public constructor(input: UserIdentifier | string | undefined = undefined) { + if (input instanceof UserIdentifier) { + if (input.seed !== undefined) { + this.seed = input.seed.seed + } else { + this.communityUuid = input.communityUuid + this.userUuid = input.communityUser?.uuid + this.accountNr = input.communityUser?.accountNr + } + } else if (typeof input === 'string') { + this.communityUuid = input + } + } + + isCommunityKeyPair(): boolean { + return this.communityUuid !== undefined && this.userUuid === undefined + } + + isSeedKeyPair(): boolean { + return this.seed !== undefined + } + + isUserKeyPair(): boolean { + return ( + this.communityUuid !== undefined && + this.userUuid !== undefined && + this.accountNr === undefined + ) + } + + isAccountKeyPair(): boolean { + return ( + this.communityUuid !== undefined && + this.userUuid !== undefined && + this.accountNr !== undefined + ) + } + + getKey(): string { + if (this.seed && this.isSeedKeyPair()) { + return this.seed + } else if (this.communityUuid && this.isCommunityKeyPair()) { + return this.communityUuid + } + if (this.userUuid && this.communityUuid) { + const communityUserHash = uuid4sToMemoryBlock([this.userUuid, this.communityUuid]) + .calculateHash() + .convertToHex() + if (this.isUserKeyPair()) { + return communityUserHash + } + if (this.accountNr && this.isAccountKeyPair()) { + return communityUserHash + this.accountNr.toString() + } + } + throw new LogError('KeyPairIdentifier: unhandled input type', this) + } +} diff --git a/dlt-connector/src/graphql/const.ts b/dlt-connector/src/graphql/const.ts new file mode 100644 index 000000000..ce7186a54 --- /dev/null +++ b/dlt-connector/src/graphql/const.ts @@ -0,0 +1,2 @@ +export const MEMO_MAX_CHARS = 255 +export const MEMO_MIN_CHARS = 5 diff --git a/dlt-connector/src/graphql/enum/InputTransactionType.ts b/dlt-connector/src/graphql/enum/InputTransactionType.ts index 20e5e40f9..f1b56823e 100755 --- a/dlt-connector/src/graphql/enum/InputTransactionType.ts +++ b/dlt-connector/src/graphql/enum/InputTransactionType.ts @@ -8,6 +8,7 @@ export enum InputTransactionType { GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', REGISTER_ADDRESS = 'REGISTER_ADDRESS', GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', + GRADIDO_REDEEM_DEFERRED_TRANSFER = 'GRADIDO_REDEEM_DEFERRED_TRANSFER', COMMUNITY_ROOT = 'COMMUNITY_ROOT', } diff --git a/dlt-connector/src/graphql/enum/TransactionErrorType.ts b/dlt-connector/src/graphql/enum/TransactionErrorType.ts index 5a8a2a06b..f89df4afe 100644 --- a/dlt-connector/src/graphql/enum/TransactionErrorType.ts +++ b/dlt-connector/src/graphql/enum/TransactionErrorType.ts @@ -5,6 +5,7 @@ import { registerEnumType } from 'type-graphql' export enum TransactionErrorType { NOT_IMPLEMENTED_YET = 'Not Implemented yet', MISSING_PARAMETER = 'Missing parameter', + INVALID_PARAMETER = 'Invalid parameter', ALREADY_EXIST = 'Already exist', DB_ERROR = 'DB Error', PROTO_DECODE_ERROR = 'Proto Decode Error', diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 3b2099ab6..0306d70e0 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,9 +1,10 @@ // https://www.npmjs.com/package/@apollo/protobufjs import { InputTransactionType } from '@enum/InputTransactionType' import { isValidDateString, isValidNumberString } from '@validator/DateString' -import { IsEnum, IsObject, ValidateNested } from 'class-validator' +import { IsEnum, IsObject, IsPositive, MaxLength, MinLength, ValidateNested } from 'class-validator' import { InputType, Field } from 'type-graphql' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from '@/graphql//const' import { AccountType } from '@/graphql/enum/AccountType' import { UserIdentifier } from './UserIdentifier' @@ -26,6 +27,11 @@ export class TransactionDraft { @isValidNumberString() amount?: string + @Field(() => String, { nullable: true }) + @MaxLength(MEMO_MAX_CHARS) + @MinLength(MEMO_MIN_CHARS) + memo?: string + @Field(() => InputTransactionType) @IsEnum(InputTransactionType) type: InputTransactionType @@ -40,9 +46,10 @@ export class TransactionDraft { targetDate?: string // only for deferred transaction - @Field(() => String, { nullable: true }) - @isValidDateString() - timeoutDate?: string + // duration in seconds + @Field(() => Number, { nullable: true }) + @IsPositive() + timeoutDuration?: number // only for register address @Field(() => AccountType, { nullable: true }) diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts index ab7203285..3db0ac26b 100644 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ b/dlt-connector/src/graphql/resolver/AccountsResolver.ts @@ -3,9 +3,9 @@ import { AddressType_NONE } from 'gradido-blockchain-js' import { Arg, Query, Resolver } from 'type-graphql' import { getAddressType } from '@/client/GradidoNode' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { KeyPairCalculation } from '@/interactions/keyPairCalculation/KeyPairCalculation.context' import { logger } from '@/logging/logger' -import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' import { uuid4ToHash } from '@/utils/typeConverter' import { TransactionErrorType } from '../enum/TransactionErrorType' @@ -17,7 +17,7 @@ import { TransactionResult } from '../model/TransactionResult' export class AccountResolver { @Query(() => Boolean) async isAccountExist(@Arg('data') userIdentifier: UserIdentifier): Promise { - const accountKeyPair = await KeyPairCalculation(userIdentifier) + const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifier(userIdentifier)) const publicKey = accountKeyPair.getPublicKey() if (!publicKey) { throw new TransactionResult( diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts index 68dd65a21..fb062b011 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -26,6 +26,6 @@ export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { if (!communityRoot) { throw new LogError('invalid confirmed transaction') } - return new KeyPairEd25519(communityRoot.getPubkey()) + return new KeyPairEd25519(communityRoot.getPublicKey()) } } diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index 3cb1f43cf..0f9137453 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -1,8 +1,9 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { UserIdentifier } from '@/graphql/input/UserIdentifier' import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' +import { LogError } from '@/server/LogError' import { AccountKeyPairRole } from './AccountKeyPair.role' import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' @@ -15,7 +16,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' * @DCI-Context * Context for calculating key pair for signing transactions */ -export async function KeyPairCalculation(input: UserIdentifier | string): Promise { +export async function KeyPairCalculation(input: KeyPairIdentifier): Promise { const cache = KeyPairCacheManager.getInstance() // Try cache lookup first @@ -24,33 +25,49 @@ export async function KeyPairCalculation(input: UserIdentifier | string): Promis return keyPair } - const retrieveKeyPair = async (input: UserIdentifier | string): Promise => { - if (input instanceof UserIdentifier && input.seed) { - return new LinkedTransactionKeyPairRole(input.seed.seed).generateKeyPair() + const retrieveKeyPair = async (input: KeyPairIdentifier): Promise => { + if (input.isSeedKeyPair() && input.seed) { + return new LinkedTransactionKeyPairRole(input.seed).generateKeyPair() + } + if (!input.communityUuid) { + throw new LogError('missing community id') } - - const communityUUID = input instanceof UserIdentifier ? input.communityUuid : input - // If input does not belong to the home community, handle as remote key pair - if (cache.getHomeCommunityUUID() !== communityUUID) { + if (cache.getHomeCommunityUUID() !== input.communityUuid) { const role = input instanceof UserIdentifier ? new RemoteAccountKeyPairRole(input) - : new ForeignCommunityKeyPairRole(input) + : new ForeignCommunityKeyPairRole(input.communityUuid) return await role.retrieveKeyPair() } - let communityKeyPair = cache.findKeyPair(communityUUID) + let communityKeyPair = cache.findKeyPair(input) if (!communityKeyPair) { communityKeyPair = new HomeCommunityKeyPairRole().generateKeyPair() - cache.addKeyPair(communityUUID, communityKeyPair) } - if (input instanceof UserIdentifier) { - const userKeyPair = new UserKeyPairRole(input, communityKeyPair).generateKeyPair() - const accountNr = input.communityUser?.accountNr ?? 1 - return new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() + if (input.isCommunityKeyPair()) { + return communityKeyPair } - return communityKeyPair + const userKeyPairIdentifier = new KeyPairIdentifier() + userKeyPairIdentifier.communityUuid = input.communityUuid + userKeyPairIdentifier.userUuid = input.userUuid + + let userKeyPair = cache.findKeyPair(userKeyPairIdentifier) + if (!userKeyPair && userKeyPairIdentifier.userUuid) { + userKeyPair = new UserKeyPairRole( + userKeyPairIdentifier.userUuid, + communityKeyPair, + ).generateKeyPair() + } + if (!userKeyPair) { + throw new LogError("couldn't generate user key pair") + } + if (input.isUserKeyPair()) { + return userKeyPair + } + + const accountNr = input.accountNr ?? 1 + return new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() } keyPair = await retrieveKeyPair(input) diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts index 6f433a7df..ca724fc99 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -1,24 +1,20 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { LogError } from '@/server/LogError' import { hardenDerivationIndex } from '@/utils/derivationHelper' import { uuid4ToBuffer } from '@/utils/typeConverter' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class UserKeyPairRole extends AbstractKeyPairRole { - public constructor(private user: UserIdentifier, private communityKeys: KeyPairEd25519) { + public constructor(private userUuid: string, private communityKeys: KeyPairEd25519) { super() } public generateKeyPair(): KeyPairEd25519 { // example gradido id: 03857ac1-9cc2-483e-8a91-e5b10f5b8d16 => // wholeHex: '03857ac19cc2483e8a91e5b10f5b8d16'] - if (!this.user.communityUser) { - throw new LogError('missing community user') - } - const wholeHex = uuid4ToBuffer(this.user.communityUser.uuid) + + const wholeHex = uuid4ToBuffer(this.userUuid) const parts = [] for (let i = 0; i < 4; i++) { parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts index 713a2b906..a1a7b237d 100644 --- a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts @@ -1,5 +1,6 @@ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { CommunityDraft } from '@/graphql/input/CommunityDraft' import { LogError } from '@/server/LogError' import { @@ -27,7 +28,7 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const communityKeyPair = await KeyPairCalculation(this.self.uuid) + const communityKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.uuid)) const gmwKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), ) diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index 2865193a9..e3fa9a838 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -1,8 +1,16 @@ -import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { + AuthenticatedEncryption, + EncryptedMemo, + GradidoTransactionBuilder, + GradidoUnit, + TransferAmount, +} from 'gradido-blockchain-js' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { TransactionError } from '@/graphql/model/TransactionError' +import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' @@ -40,15 +48,25 @@ export class CreationTransactionRole extends AbstractTransactionRole { if (!this.self.amount) { throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'creation: amount missing') } + if (!this.self.memo) { + throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'creation: memo missing') + } + const builder = new GradidoTransactionBuilder() - const recipientKeyPair = await KeyPairCalculation(this.self.user) - const signerKeyPair = await KeyPairCalculation(this.self.linkedUser) + const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) + const signerKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.linkedUser)) + const homeCommunityKeyPair = await KeyPairCalculation( + new KeyPairIdentifier(KeyPairCacheManager.getInstance().getHomeCommunityUUID()), + ) builder .setCreatedAt(new Date(this.self.createdAt)) - .setMemo('dummy memo for creation') + .addMemo(new EncryptedMemo(this.self.memo, new AuthenticatedEncryption(homeCommunityKeyPair))) .setTransactionCreation( - new TransferAmount(recipientKeyPair.getPublicKey(), this.self.amount.toString()), + new TransferAmount( + recipientKeyPair.getPublicKey(), + GradidoUnit.fromString(this.self.amount), + ), new Date(this.self.targetDate), ) .sign(signerKeyPair) diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 511efa869..19b4dc649 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,5 +1,13 @@ -import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { + AuthenticatedEncryption, + EncryptedMemo, + GradidoTransactionBuilder, + GradidoTransfer, + GradidoUnit, + TransferAmount, +} from 'gradido-blockchain-js' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { TransactionError } from '@/graphql/model/TransactionError' @@ -37,27 +45,42 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { 'deferred transfer: amount missing', ) } - if (!this.self.timeoutDate) { + if (!this.self.memo) { throw new TransactionError( TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: timeout date missing', + 'deferred transfer: memo missing', + ) + } + if (!this.self.timeoutDuration) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'deferred transfer: timeout duration missing', ) } const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) + const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) + const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.linkedUser)) builder .setCreatedAt(new Date(this.self.createdAt)) - .setMemo('dummy memo for transfer') + .addMemo( + new EncryptedMemo( + this.self.memo, + new AuthenticatedEncryption(senderKeyPair), + new AuthenticatedEncryption(recipientKeyPair), + ), + ) .setDeferredTransfer( new GradidoTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), + new TransferAmount( + senderKeyPair.getPublicKey(), + GradidoUnit.fromString(this.self.amount), + ), recipientKeyPair.getPublicKey(), ), - new Date(this.self.timeoutDate), + this.self.timeoutDuration, ) - builder.sign(senderKeyPair) + .sign(senderKeyPair) return builder } } diff --git a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts new file mode 100644 index 000000000..eb858c322 --- /dev/null +++ b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts @@ -0,0 +1,103 @@ +import { + GradidoTransactionBuilder, + GradidoTransfer, + GradidoUnit, + TransferAmount, +} from 'gradido-blockchain-js' + +import { getTransactionsForAccount } from '@/client/GradidoNode' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' +import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' +import { TransactionDraft } from '@/graphql/input/TransactionDraft' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { TransactionError } from '@/graphql/model/TransactionError' +import { communityUuidToTopic, uuid4ToHash } from '@/utils/typeConverter' + +import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' + +import { AbstractTransactionRole } from './AbstractTransaction.role' + +export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRole { + private linkedUser: UserIdentifier + constructor(protected self: TransactionDraft) { + super() + if (!this.self.linkedUser) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'transfer: linked user missing', + ) + } + this.linkedUser = this.self.linkedUser + } + + getSenderCommunityUuid(): string { + return this.self.user.communityUuid + } + + getRecipientCommunityUuid(): string { + return this.linkedUser.communityUuid + } + + public async getGradidoTransactionBuilder(): Promise { + if (!this.self.amount) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'redeem deferred transfer: amount missing', + ) + } + const builder = new GradidoTransactionBuilder() + const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) + const senderPublicKey = senderKeyPair.getPublicKey() + if (!senderPublicKey) { + throw new TransactionError( + TransactionErrorType.INVALID_PARAMETER, + "redeem deferred transfer: couldn't calculate sender public key", + ) + } + // load deferred transfer transaction from gradido node + const transactions = await getTransactionsForAccount( + senderPublicKey, + communityUuidToTopic(this.getSenderCommunityUuid()), + ) + if (!transactions || transactions.length !== 1) { + throw new TransactionError( + TransactionErrorType.NOT_FOUND, + "redeem deferred transfer: couldn't find deferred transfer on Gradido Node", + ) + } + const deferredTransfer = transactions[0] + const deferredTransferBody = deferredTransfer.getGradidoTransaction()?.getTransactionBody() + if (!deferredTransferBody) { + throw new TransactionError( + TransactionErrorType.NOT_FOUND, + "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", + ) + } + const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.linkedUser)) + + // TODO: fix getMemos in gradido-blockchain-js to return correct data + builder + .setCreatedAt(new Date(this.self.createdAt)) + .addMemo(deferredTransferBody.getMemos()[0]) + .setRedeemDeferredTransfer( + deferredTransfer.getId(), + new GradidoTransfer( + new TransferAmount( + senderKeyPair.getPublicKey(), + GradidoUnit.fromString(this.self.amount), + ), + recipientKeyPair.getPublicKey(), + ), + ) + const senderCommunity = this.self.user.communityUuid + const recipientCommunity = this.linkedUser.communityUuid + if (senderCommunity !== recipientCommunity) { + // we have a cross group transaction + builder + .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) + .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) + } + builder.sign(senderKeyPair) + return builder + } +} diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts index f8c82586d..70d612e08 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -1,6 +1,7 @@ /* eslint-disable camelcase */ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { TransactionError } from '@/graphql/model/TransactionError' @@ -40,17 +41,25 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { } const builder = new GradidoTransactionBuilder() - const communityKeyPair = await KeyPairCalculation(this.self.user.communityUuid) - const accountKeyPair = await KeyPairCalculation(this.self.user) + const communityKeyPair = await KeyPairCalculation( + new KeyPairIdentifier(this.self.user.communityUuid), + ) + const keyPairIdentifer = new KeyPairIdentifier(this.self.user) + const accountKeyPair = await KeyPairCalculation(keyPairIdentifer) + // unsetting accountNr change identifier from account key pair to user key pair + keyPairIdentifer.accountNr = undefined + const userKeyPair = await KeyPairCalculation(keyPairIdentifer) builder .setCreatedAt(new Date(this.self.createdAt)) .setRegisterAddress( - accountKeyPair.getPublicKey(), + userKeyPair.getPublicKey(), accountTypeToAddressType(this.self.accountType), uuid4ToHash(this.self.user.communityUser.uuid), + accountKeyPair.getPublicKey(), ) .sign(communityKeyPair) .sign(accountKeyPair) + .sign(userKeyPair) return builder } } diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index be02eef55..2607f6c8f 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -17,12 +17,13 @@ import { TransactionRecipe } from '@/graphql/model/TransactionRecipe' import { TransactionResult } from '@/graphql/model/TransactionResult' import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' +import { communityUuidToTopic } from '@/utils/typeConverter' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.role' +import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' @@ -87,6 +88,9 @@ export async function SendToIotaContext( case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: role = new DeferredTransferTransactionRole(input) break + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + role = new RedeemDeferredTransferTransactionRole(input) + break default: throw new TransactionError( TransactionErrorType.NOT_IMPLEMENTED_YET, @@ -104,22 +108,19 @@ export async function SendToIotaContext( validate(outboundTransaction) const outboundIotaMessageId = await sendViaIota( outboundTransaction, - uuid4ToHash(role.getSenderCommunityUuid()).convertToHex(), + communityUuidToTopic(role.getSenderCommunityUuid()), ) builder.setParentMessageId(outboundIotaMessageId) const inboundTransaction = builder.buildInbound() validate(inboundTransaction) - await sendViaIota( - inboundTransaction, - uuid4ToHash(role.getRecipientCommunityUuid()).convertToHex(), - ) + await sendViaIota(inboundTransaction, communityUuidToTopic(role.getRecipientCommunityUuid())) return new TransactionResult(new TransactionRecipe(outboundTransaction, outboundIotaMessageId)) } else { const transaction = builder.build() validate(transaction) const iotaMessageId = await sendViaIota( transaction, - uuid4ToHash(role.getSenderCommunityUuid()).convertToHex(), + communityUuidToTopic(role.getSenderCommunityUuid()), ) return new TransactionResult(new TransactionRecipe(transaction, iotaMessageId)) } diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index 7a4cd7bb0..dd730f590 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -1,5 +1,12 @@ -import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js' +import { + AuthenticatedEncryption, + EncryptedMemo, + GradidoTransactionBuilder, + GradidoUnit, + TransferAmount, +} from 'gradido-blockchain-js' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' import { TransactionDraft } from '@/graphql/input/TransactionDraft' import { UserIdentifier } from '@/graphql/input/UserIdentifier' @@ -35,14 +42,27 @@ export class TransferTransactionRole extends AbstractTransactionRole { if (!this.self.amount) { throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'transfer: amount missing') } + if (!this.self.memo) { + throw new TransactionError( + TransactionErrorType.MISSING_PARAMETER, + 'deferred transfer: memo missing', + ) + } const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(this.self.user) - const recipientKeyPair = await KeyPairCalculation(this.linkedUser) + const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) + const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.linkedUser)) + builder .setCreatedAt(new Date(this.self.createdAt)) - .setMemo('dummy memo for transfer') + .addMemo( + new EncryptedMemo( + this.self.memo, + new AuthenticatedEncryption(senderKeyPair), + new AuthenticatedEncryption(recipientKeyPair), + ), + ) .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), + new TransferAmount(senderKeyPair.getPublicKey(), GradidoUnit.fromString(this.self.amount)), recipientKeyPair.getPublicKey(), ) const senderCommunity = this.self.user.communityUuid diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/manager/KeyPairCacheManager.ts index f492d127b..c3613f91d 100644 --- a/dlt-connector/src/manager/KeyPairCacheManager.ts +++ b/dlt-connector/src/manager/KeyPairCacheManager.ts @@ -1,8 +1,7 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -45,30 +44,19 @@ export class KeyPairCacheManager { return this.homeCommunityUUID } - public findKeyPair(input: UserIdentifier | string): KeyPairEd25519 | undefined { - return this.cache.get(this.getKey(input)) + public findKeyPair(input: KeyPairIdentifier): KeyPairEd25519 | undefined { + return this.cache.get(input.getKey()) } - public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void { - const key = this.getKey(input) + public addKeyPair(input: KeyPairIdentifier, keyPair: KeyPairEd25519): void { + const key = input.getKey() if (this.cache.has(key)) { - logger.warn('key already exist, cannot add', key) + logger.warn('key already exist, cannot add', { + key, + publicKey: keyPair.getPublicKey()?.convertToHex(), + }) return } this.cache.set(key, keyPair) } - - protected getKey(input: UserIdentifier | string): string { - if (input instanceof UserIdentifier) { - if (input.communityUser) { - return input.communityUser.uuid - } else if (input.seed) { - return input.seed.seed - } - throw new LogError('unhandled branch') - } else if (typeof input === 'string') { - return input - } - throw new LogError('unhandled input type') - } } diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 198c15042..219b95376 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -32,6 +32,14 @@ export const uuid4ToMemoryBlock = (uuid: string): MemoryBlock => { return MemoryBlock.fromHex(uuid.replace(/-/g, '')) } +export const uuid4sToMemoryBlock = (uuid: string[]): MemoryBlock => { + let resultHexString = '' + for (let i = 0; i < uuid.length; i++) { + resultHexString += uuid[i].replace(/-/g, '') + } + return MemoryBlock.fromHex(resultHexString) +} + export const uuid4ToHash = (communityUUID: string): MemoryBlock => { return uuid4ToMemoryBlock(communityUUID).calculateHash() } @@ -40,6 +48,10 @@ export const base64ToBuffer = (base64: string): Buffer => { return Buffer.from(base64, 'base64') } +export const communityUuidToTopic = (communityUUID: string): string => { + return uuid4ToHash(communityUUID).convertToHex() +} + export function getEnumValue>( enumType: T, value: number | string, diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock index c4f244816..71cde5091 100644 --- a/dlt-connector/yarn.lock +++ b/dlt-connector/yarn.lock @@ -3277,9 +3277,9 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -"gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js#master": +"gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js#1c75576": version "0.0.1" - resolved "git+https://github.com/gradido/gradido-blockchain-js#5e7bc50af82d30ef0fdbe48414b1f916c592b6f4" + resolved "git+https://github.com/gradido/gradido-blockchain-js#1c755763b7f3f71c2ee9f396da5e9512fa666ee4" dependencies: bindings "^1.5.0" nan "^2.20.0" From 93e327170532ce7ce6f8f151f9513d67ed039589 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 14 Jan 2025 16:45:01 +0100 Subject: [PATCH 022/226] changes for adapting to gradido blockchain changes --- .../dltConnector/enum/DltTransactionType.ts | 1 + .../transactionToDlt/TransactionToDlt.role.ts | 20 ++++++++++--------- .../transactionToDlt.context.ts | 17 ++++++++++++---- .../sendTransactionsToDltConnector.ts | 7 +++++-- database/migrations/0088-merge_dlt_tables.ts | 2 +- .../DeferredTransferTransaction.role.ts | 7 +++++-- .../RedeemDeferredTransferTransaction.role.ts | 6 ++++-- 7 files changed, 40 insertions(+), 20 deletions(-) diff --git a/backend/src/apis/dltConnector/enum/DltTransactionType.ts b/backend/src/apis/dltConnector/enum/DltTransactionType.ts index 80e12daa5..ce1044a7a 100644 --- a/backend/src/apis/dltConnector/enum/DltTransactionType.ts +++ b/backend/src/apis/dltConnector/enum/DltTransactionType.ts @@ -1,4 +1,5 @@ export enum DltTransactionType { + UNKNOWN = 0, REGISTER_ADDRESS = 1, CREATION = 2, TRANSFER = 3, diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts index eb6658835..de96d38cc 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts @@ -48,15 +48,6 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole { await transactionToDlt(dltConnector) await InterruptiveSleepManager.getInstance().sleep( TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, - 1000, + // TODO: put sleep time into config, because it influence performance, + // transactionToDlt call 4 db queries to look for new transactions + CONFIG.PRODUCTION ? 100000 : 1000, ) } catch (e) { // couldn't connect to dlt-connector? We wait diff --git a/database/migrations/0088-merge_dlt_tables.ts b/database/migrations/0088-merge_dlt_tables.ts index ab3db11eb..70ee2d49e 100644 --- a/database/migrations/0088-merge_dlt_tables.ts +++ b/database/migrations/0088-merge_dlt_tables.ts @@ -7,7 +7,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ALTER TABLE \`dlt_transactions\` CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL, ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, - ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\` + ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`, ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\` ; `) diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 19b4dc649..90783723e 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,5 +1,6 @@ import { AuthenticatedEncryption, + DurationSeconds, EncryptedMemo, GradidoTransactionBuilder, GradidoTransfer, @@ -74,11 +75,13 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), - GradidoUnit.fromString(this.self.amount), + GradidoUnit.fromString(this.self.amount).calculateCompoundInterest( + this.self.timeoutDuration, + ), ), recipientKeyPair.getPublicKey(), ), - this.self.timeoutDuration, + new DurationSeconds(this.self.timeoutDuration), ) .sign(senderKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts index eb858c322..ae9115485 100644 --- a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts @@ -75,10 +75,8 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo } const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.linkedUser)) - // TODO: fix getMemos in gradido-blockchain-js to return correct data builder .setCreatedAt(new Date(this.self.createdAt)) - .addMemo(deferredTransferBody.getMemos()[0]) .setRedeemDeferredTransfer( deferredTransfer.getId(), new GradidoTransfer( @@ -89,6 +87,10 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo recipientKeyPair.getPublicKey(), ), ) + const memos = deferredTransferBody.getMemos() + for (let i = 0; i < memos.size(); i++) { + builder.addMemo(memos.get(i)) + } const senderCommunity = this.self.user.communityUuid const recipientCommunity = this.linkedUser.communityUuid if (senderCommunity !== recipientCommunity) { From 0306fab49aee92bfc85b69b1796e139590ab9733 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 30 Jun 2025 07:23:01 +0200 Subject: [PATCH 023/226] update database for dlt connector --- .../DltTransaction.ts | 0 .../DltUser.ts | 0 .../User.ts | 3 ++- .../DltTransaction.ts | 0 .../Transaction.ts | 0 .../TransactionLink.ts | 0 .../User.ts | 0 database/entity/DltTransaction.ts | 2 +- database/entity/DltUser.ts | 1 - database/entity/Transaction.ts | 2 +- database/entity/TransactionLink.ts | 2 +- database/entity/User.ts | 2 +- database/logging/DltUserLogging.view.ts | 23 ------------------- ...s_table.ts => 0088-add_dlt_users_table.ts} | 0 ...dlt_tables.ts => 0089-merge_dlt_tables.ts} | 0 15 files changed, 6 insertions(+), 29 deletions(-) rename database/entity/{0087-add_dlt_users_table => 0088-add_dlt_users_table}/DltTransaction.ts (100%) rename database/entity/{0087-add_dlt_users_table => 0088-add_dlt_users_table}/DltUser.ts (100%) rename database/entity/{0087-add_dlt_users_table => 0088-add_dlt_users_table}/User.ts (98%) rename database/entity/{0088-merge_dlt_tables => 0089-merge_dlt_tables}/DltTransaction.ts (100%) rename database/entity/{0088-merge_dlt_tables => 0089-merge_dlt_tables}/Transaction.ts (100%) rename database/entity/{0088-merge_dlt_tables => 0089-merge_dlt_tables}/TransactionLink.ts (100%) rename database/entity/{0088-merge_dlt_tables => 0089-merge_dlt_tables}/User.ts (100%) delete mode 100644 database/entity/DltUser.ts delete mode 100644 database/logging/DltUserLogging.view.ts rename database/migrations/{0087-add_dlt_users_table.ts => 0088-add_dlt_users_table.ts} (100%) rename database/migrations/{0088-merge_dlt_tables.ts => 0089-merge_dlt_tables.ts} (100%) diff --git a/database/entity/0087-add_dlt_users_table/DltTransaction.ts b/database/entity/0088-add_dlt_users_table/DltTransaction.ts similarity index 100% rename from database/entity/0087-add_dlt_users_table/DltTransaction.ts rename to database/entity/0088-add_dlt_users_table/DltTransaction.ts diff --git a/database/entity/0087-add_dlt_users_table/DltUser.ts b/database/entity/0088-add_dlt_users_table/DltUser.ts similarity index 100% rename from database/entity/0087-add_dlt_users_table/DltUser.ts rename to database/entity/0088-add_dlt_users_table/DltUser.ts diff --git a/database/entity/0087-add_dlt_users_table/User.ts b/database/entity/0088-add_dlt_users_table/User.ts similarity index 98% rename from database/entity/0087-add_dlt_users_table/User.ts rename to database/entity/0088-add_dlt_users_table/User.ts index 8d5466241..f9b079a04 100644 --- a/database/entity/0087-add_dlt_users_table/User.ts +++ b/database/entity/0088-add_dlt_users_table/User.ts @@ -16,7 +16,8 @@ import { UserContact } from '../UserContact' import { UserRole } from '../UserRole' import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' import { Community } from '../Community' -import { DltUser } from '../DltUser' +// removed in current version +import { DltUser } from './DltUser' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { diff --git a/database/entity/0088-merge_dlt_tables/DltTransaction.ts b/database/entity/0089-merge_dlt_tables/DltTransaction.ts similarity index 100% rename from database/entity/0088-merge_dlt_tables/DltTransaction.ts rename to database/entity/0089-merge_dlt_tables/DltTransaction.ts diff --git a/database/entity/0088-merge_dlt_tables/Transaction.ts b/database/entity/0089-merge_dlt_tables/Transaction.ts similarity index 100% rename from database/entity/0088-merge_dlt_tables/Transaction.ts rename to database/entity/0089-merge_dlt_tables/Transaction.ts diff --git a/database/entity/0088-merge_dlt_tables/TransactionLink.ts b/database/entity/0089-merge_dlt_tables/TransactionLink.ts similarity index 100% rename from database/entity/0088-merge_dlt_tables/TransactionLink.ts rename to database/entity/0089-merge_dlt_tables/TransactionLink.ts diff --git a/database/entity/0088-merge_dlt_tables/User.ts b/database/entity/0089-merge_dlt_tables/User.ts similarity index 100% rename from database/entity/0088-merge_dlt_tables/User.ts rename to database/entity/0089-merge_dlt_tables/User.ts diff --git a/database/entity/DltTransaction.ts b/database/entity/DltTransaction.ts index 373e5f593..bc3244dc0 100644 --- a/database/entity/DltTransaction.ts +++ b/database/entity/DltTransaction.ts @@ -1 +1 @@ -export { DltTransaction } from './0088-merge_dlt_tables/DltTransaction' +export { DltTransaction } from './0089-merge_dlt_tables/DltTransaction' diff --git a/database/entity/DltUser.ts b/database/entity/DltUser.ts deleted file mode 100644 index 29c835233..000000000 --- a/database/entity/DltUser.ts +++ /dev/null @@ -1 +0,0 @@ -export { DltUser } from './0087-add_dlt_users_table/DltUser' diff --git a/database/entity/Transaction.ts b/database/entity/Transaction.ts index 7b014e17a..2f4b2ccfc 100644 --- a/database/entity/Transaction.ts +++ b/database/entity/Transaction.ts @@ -1 +1 @@ -export { Transaction } from './0088-merge_dlt_tables/Transaction' +export { Transaction } from './0089-merge_dlt_tables/Transaction' diff --git a/database/entity/TransactionLink.ts b/database/entity/TransactionLink.ts index ff69e101f..fa8af166d 100644 --- a/database/entity/TransactionLink.ts +++ b/database/entity/TransactionLink.ts @@ -1 +1 @@ -export { TransactionLink } from './0088-merge_dlt_tables/TransactionLink' +export { TransactionLink } from './0089-merge_dlt_tables/TransactionLink' diff --git a/database/entity/User.ts b/database/entity/User.ts index 3836c683e..92b529cb1 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0088-merge_dlt_tables/User' +export { User } from './0089-merge_dlt_tables/User' diff --git a/database/logging/DltUserLogging.view.ts b/database/logging/DltUserLogging.view.ts deleted file mode 100644 index c98c3f351..000000000 --- a/database/logging/DltUserLogging.view.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DltUser } from '../entity/DltUser' -import { AbstractLoggingView } from './AbstractLogging.view' -import { UserLoggingView } from './UserLogging.view' - -export class DltUserLoggingView extends AbstractLoggingView { - public constructor(private self: DltUser) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - id: this.self.id, - user: this.self.user - ? new UserLoggingView(this.self.user).toJSON() - : { id: this.self.userId }, - messageId: this.self.messageId, - verified: this.self.verified, - createdAt: this.dateToString(this.self.createdAt), - verifiedAt: this.dateToString(this.self.verifiedAt), - } - } -} diff --git a/database/migrations/0087-add_dlt_users_table.ts b/database/migrations/0088-add_dlt_users_table.ts similarity index 100% rename from database/migrations/0087-add_dlt_users_table.ts rename to database/migrations/0088-add_dlt_users_table.ts diff --git a/database/migrations/0088-merge_dlt_tables.ts b/database/migrations/0089-merge_dlt_tables.ts similarity index 100% rename from database/migrations/0088-merge_dlt_tables.ts rename to database/migrations/0089-merge_dlt_tables.ts From 78351257ee47fa656baa4816e7e298cbc174955e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 3 Jul 2025 15:35:42 +0200 Subject: [PATCH 024/226] refactor with extensive, experimental use of valibot for typecheck, vailidation and conversation --- .gitignore | 2 +- .../TransactionLinkToDlt.role.ts | 3 +- dlt-connector/.env.template | 21 - dlt-connector/.eslintignore | 4 - dlt-connector/.eslintrc.js | 207 - dlt-connector/.gitignore | 8 - dlt-connector/.nvmrc | 1 - dlt-connector/.prettierrc.js | 9 - dlt-connector/@types/bip32-ed25519/index.d.ts | 1 - dlt-connector/Dockerfile | 119 - dlt-connector/README.md | 1 + dlt-connector/bun.lock | 577 ++ dlt-connector/jest.config.js | 37 - dlt-connector/log4js-config.json | 6 +- dlt-connector/package.json | 97 +- dlt-connector/schema.graphql | 98 - .../src/{manager => }/KeyPairCacheManager.ts | 43 +- dlt-connector/src/client/BackendClient.ts | 86 +- dlt-connector/src/client/GradidoNode.ts | 156 - .../src/client/GradidoNode/input.schema.ts | 33 + .../src/client/GradidoNode/jsonrpc.api.ts | 174 + .../src/client/GradidoNode/output.schema.ts | 0 dlt-connector/src/client/IotaClient.test.ts | 71 - dlt-connector/src/client/IotaClient.ts | 53 - dlt-connector/src/config/const.ts | 1 + dlt-connector/src/config/index.ts | 61 +- .../src/data/KeyPairIdentifier.logic.ts | 97 + dlt-connector/src/data/KeyPairIdentifier.ts | 72 - .../src/{graphql => }/enum/AccountType.ts | 7 - dlt-connector/src/enum/AddressType.ts | 19 + .../src/enum/GradidoNodeErrorCodes.ts | 20 + .../enum/InputTransactionType.ts | 7 - .../enum/TransactionErrorType.ts | 7 - dlt-connector/src/errors.ts | 43 + dlt-connector/src/graphql/arg/CommunityArg.ts | 19 - dlt-connector/src/graphql/const.ts | 2 - .../src/graphql/input/CommunityDraft.ts | 20 - .../src/graphql/input/CommunityUser.ts | 15 - .../src/graphql/input/IdentifierSeed.ts | 15 - .../src/graphql/input/TransactionDraft.ts | 58 - .../src/graphql/input/UserIdentifier.ts | 24 - .../src/graphql/model/TransactionError.ts | 21 - .../src/graphql/model/TransactionRecipe.ts | 27 - .../src/graphql/model/TransactionResult.ts | 28 - .../src/graphql/resolver/AccountsResolver.ts | 36 - .../graphql/resolver/TransactionsResolver.ts | 27 - dlt-connector/src/graphql/schema.ts | 19 - .../src/graphql/validator/DateString.ts | 41 - dlt-connector/src/index.ts | 105 +- .../AbstractRemoteKeyPair.role.ts | 6 + .../ForeignCommunityKeyPair.role.ts | 37 +- .../HomeCommunityKeyPair.role.ts | 10 +- .../KeyPairCalculation.context.ts | 70 +- .../LinkedTransactionKeyPair.role.ts | 5 +- .../RemoteAccountKeyPair.role.ts | 40 +- .../keyPairCalculation/UserKeyPair.role.ts | 6 +- .../CommunityRootTransaction.role.ts | 21 +- .../sendToIota/CreationTransaction.role.ts | 90 +- .../DeferredTransferTransaction.role.ts | 73 +- .../RegisterAddressTransaction.role.ts | 73 +- .../sendToIota/TransferTransaction.role.ts | 62 +- .../src/logging/AbstractLogging.view.ts | 38 - .../src/logging/CommunityUserLogging.view.ts | 17 - .../src/logging/IdentifierSeedLogging.view.ts | 16 - .../logging/TransactionDraftLogging.view.ts | 28 - .../src/logging/UserIdentifierLogging.view.ts | 22 - dlt-connector/src/logging/logger.ts | 13 - dlt-connector/src/schemas/account.schema.ts | 40 + .../src/schemas/rpcParameter.schema.test.ts | 21 + .../src/schemas/rpcParameter.schema.ts | 19 + .../src/schemas/transaction.schema.test.ts | 207 + .../src/schemas/transaction.schema.ts | 87 + .../src/schemas/typeConverter.schema.test.ts | 51 + .../src/schemas/typeConverter.schema.ts | 125 + .../src/schemas/typeGuard.schema.test.ts | 67 + dlt-connector/src/schemas/typeGuard.schema.ts | 146 + dlt-connector/src/server/LogError.test.ts | 27 - dlt-connector/src/server/LogError.ts | 10 - dlt-connector/src/server/cors.ts | 8 - dlt-connector/src/server/createServer.ts | 79 - .../src/utils/derivationHelper.test.ts | 4 +- dlt-connector/src/utils/network.ts | 51 + dlt-connector/src/utils/typeConverter.test.ts | 23 - dlt-connector/src/utils/typeConverter.ts | 120 - dlt-connector/test/ApolloServerMock.ts | 20 - dlt-connector/test/testSetup.ts | 22 - dlt-connector/tsconfig.json | 174 +- dlt-connector/types/global.d.ts | 2 + dlt-connector/yarn.lock | 6476 ----------------- 89 files changed, 2275 insertions(+), 8729 deletions(-) delete mode 100644 dlt-connector/.env.template delete mode 100644 dlt-connector/.eslintignore delete mode 100644 dlt-connector/.eslintrc.js delete mode 100644 dlt-connector/.gitignore delete mode 100644 dlt-connector/.nvmrc delete mode 100644 dlt-connector/.prettierrc.js delete mode 100644 dlt-connector/@types/bip32-ed25519/index.d.ts delete mode 100644 dlt-connector/Dockerfile create mode 100644 dlt-connector/README.md create mode 100644 dlt-connector/bun.lock delete mode 100644 dlt-connector/jest.config.js delete mode 100644 dlt-connector/schema.graphql rename dlt-connector/src/{manager => }/KeyPairCacheManager.ts (55%) delete mode 100644 dlt-connector/src/client/GradidoNode.ts create mode 100644 dlt-connector/src/client/GradidoNode/input.schema.ts create mode 100644 dlt-connector/src/client/GradidoNode/jsonrpc.api.ts create mode 100644 dlt-connector/src/client/GradidoNode/output.schema.ts delete mode 100644 dlt-connector/src/client/IotaClient.test.ts delete mode 100644 dlt-connector/src/client/IotaClient.ts create mode 100644 dlt-connector/src/config/const.ts create mode 100644 dlt-connector/src/data/KeyPairIdentifier.logic.ts delete mode 100644 dlt-connector/src/data/KeyPairIdentifier.ts rename dlt-connector/src/{graphql => }/enum/AccountType.ts (77%) create mode 100644 dlt-connector/src/enum/AddressType.ts create mode 100644 dlt-connector/src/enum/GradidoNodeErrorCodes.ts rename dlt-connector/src/{graphql => }/enum/InputTransactionType.ts (67%) rename dlt-connector/src/{graphql => }/enum/TransactionErrorType.ts (75%) create mode 100644 dlt-connector/src/errors.ts delete mode 100644 dlt-connector/src/graphql/arg/CommunityArg.ts delete mode 100644 dlt-connector/src/graphql/const.ts delete mode 100644 dlt-connector/src/graphql/input/CommunityDraft.ts delete mode 100644 dlt-connector/src/graphql/input/CommunityUser.ts delete mode 100644 dlt-connector/src/graphql/input/IdentifierSeed.ts delete mode 100755 dlt-connector/src/graphql/input/TransactionDraft.ts delete mode 100644 dlt-connector/src/graphql/input/UserIdentifier.ts delete mode 100644 dlt-connector/src/graphql/model/TransactionError.ts delete mode 100644 dlt-connector/src/graphql/model/TransactionRecipe.ts delete mode 100644 dlt-connector/src/graphql/model/TransactionResult.ts delete mode 100644 dlt-connector/src/graphql/resolver/AccountsResolver.ts delete mode 100755 dlt-connector/src/graphql/resolver/TransactionsResolver.ts delete mode 100755 dlt-connector/src/graphql/schema.ts delete mode 100644 dlt-connector/src/graphql/validator/DateString.ts delete mode 100644 dlt-connector/src/logging/AbstractLogging.view.ts delete mode 100644 dlt-connector/src/logging/CommunityUserLogging.view.ts delete mode 100644 dlt-connector/src/logging/IdentifierSeedLogging.view.ts delete mode 100644 dlt-connector/src/logging/TransactionDraftLogging.view.ts delete mode 100644 dlt-connector/src/logging/UserIdentifierLogging.view.ts delete mode 100644 dlt-connector/src/logging/logger.ts create mode 100644 dlt-connector/src/schemas/account.schema.ts create mode 100644 dlt-connector/src/schemas/rpcParameter.schema.test.ts create mode 100644 dlt-connector/src/schemas/rpcParameter.schema.ts create mode 100644 dlt-connector/src/schemas/transaction.schema.test.ts create mode 100644 dlt-connector/src/schemas/transaction.schema.ts create mode 100644 dlt-connector/src/schemas/typeConverter.schema.test.ts create mode 100644 dlt-connector/src/schemas/typeConverter.schema.ts create mode 100644 dlt-connector/src/schemas/typeGuard.schema.test.ts create mode 100644 dlt-connector/src/schemas/typeGuard.schema.ts delete mode 100644 dlt-connector/src/server/LogError.test.ts delete mode 100644 dlt-connector/src/server/LogError.ts delete mode 100644 dlt-connector/src/server/cors.ts delete mode 100755 dlt-connector/src/server/createServer.ts create mode 100644 dlt-connector/src/utils/network.ts delete mode 100644 dlt-connector/src/utils/typeConverter.test.ts delete mode 100644 dlt-connector/src/utils/typeConverter.ts delete mode 100644 dlt-connector/test/ApolloServerMock.ts delete mode 100644 dlt-connector/test/testSetup.ts create mode 100644 dlt-connector/types/global.d.ts delete mode 100644 dlt-connector/yarn.lock diff --git a/.gitignore b/.gitignore index d82288fbd..d98f0c163 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ messages.pot nbproject .metadata /out/* -/.env +.env package-lock.json /deployment/bare_metal/.env /deployment/bare_metal/nginx/sites-available/gradido.conf diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 16ba7f6f8..3d2717301 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -1,5 +1,4 @@ -import { DltTransaction } from '@entity/DltTransaction' -import { TransactionLink } from '@entity/TransactionLink' +import { DltTransaction, TransactionLink } from 'database' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template deleted file mode 100644 index ac27481bb..000000000 --- a/dlt-connector/.env.template +++ /dev/null @@ -1,21 +0,0 @@ -CONFIG_VERSION=$DLT_CONNECTOR_CONFIG_VERSION - -JWT_SECRET=$JWT_SECRET - -#IOTA -IOTA_API_URL=$IOTA_API_URL -IOTA_COMMUNITY_ALIAS=$IOTA_COMMUNITY_ALIAS -IOTA_HOME_COMMUNITY_SEED=$IOTA_HOME_COMMUNITY_SEED - -# DLT-Connector -DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT - -# Gradido Node Server URL -NODE_SERVER_URL=$NODE_SERVER_URL - -# Gradido Blockchain -GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET -GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY - -# Route to Backend -BACKEND_SERVER_URL=http://localhost:4000 \ No newline at end of file diff --git a/dlt-connector/.eslintignore b/dlt-connector/.eslintignore deleted file mode 100644 index 1ae86fe5e..000000000 --- a/dlt-connector/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -**/*.min.js -build -coverage \ No newline at end of file diff --git a/dlt-connector/.eslintrc.js b/dlt-connector/.eslintrc.js deleted file mode 100644 index fa43a5f1a..000000000 --- a/dlt-connector/.eslintrc.js +++ /dev/null @@ -1,207 +0,0 @@ -// eslint-disable-next-line import/no-commonjs, import/unambiguous -module.exports = { - root: true, - env: { - node: true, - }, - parser: '@typescript-eslint/parser', - plugins: ['prettier', '@typescript-eslint', 'import', 'n', 'promise'], - extends: [ - 'standard', - 'eslint:recommended', - 'plugin:prettier/recommended', - // 'plugin:import/recommended', - // 'plugin:import/typescript', - // 'plugin:security/recommended', - 'plugin:@eslint-community/eslint-comments/recommended', - 'plugin:dci-lint/recommended', - ], - settings: { - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - project: ['./tsconfig.json'], - }, - node: true, - }, - }, - rules: { - 'no-console': 'error', - camelcase: 'error', - 'no-debugger': 'error', - 'prettier/prettier': [ - 'error', - { - htmlWhitespaceSensitivity: 'ignore', - }, - ], - // 'dci-lint/literal-role-contracts': 'off' - // import - // 'import/export': 'error', - // 'import/no-deprecated': 'error', - // 'import/no-empty-named-blocks': 'error', - // 'import/no-extraneous-dependencies': 'error', - // 'import/no-mutable-exports': 'error', - // 'import/no-unused-modules': 'error', - // 'import/no-named-as-default': 'error', - // 'import/no-named-as-default-member': 'error', - // 'import/no-amd': 'error', - // 'import/no-commonjs': 'error', - // 'import/no-import-module-exports': 'error', - // 'import/no-nodejs-modules': 'off', - // 'import/unambiguous': 'error', - // 'import/default': 'error', - // 'import/named': 'error', - // 'import/namespace': 'error', - // 'import/no-absolute-path': 'error', - // 'import/no-cycle': 'error', - // 'import/no-dynamic-require': 'error', - // 'import/no-internal-modules': 'off', - // 'import/no-relative-packages': 'error', - // 'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }], - // 'import/no-self-import': 'error', - // 'import/no-unresolved': 'error', - // 'import/no-useless-path-segments': 'error', - // 'import/no-webpack-loader-syntax': 'error', - // 'import/consistent-type-specifier-style': 'error', - // 'import/exports-last': 'off', - // 'import/extensions': 'error', - // 'import/first': 'error', - // 'import/group-exports': 'off', - // 'import/newline-after-import': 'error', - // 'import/no-anonymous-default-export': 'error', - // 'import/no-default-export': 'error', - // 'import/no-duplicates': 'error', - // 'import/no-named-default': 'error', - // 'import/no-namespace': 'error', - // 'import/no-unassigned-import': 'error', - 'import/order': [ - 'error', - { - groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - 'newlines-between': 'always', - pathGroups: [ - { - pattern: '@?*/**', - group: 'external', - position: 'after', - }, - { - pattern: '@/**', - group: 'external', - position: 'after', - }, - ], - alphabetize: { - order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */, - caseInsensitive: true /* ignore case. Options: [true, false] */, - }, - distinctGroup: true, - }, - ], - // 'import/prefer-default-export': 'off', - // n - 'n/handle-callback-err': 'error', - 'n/no-callback-literal': 'error', - 'n/no-exports-assign': 'error', - 'n/no-extraneous-import': 'error', - 'n/no-extraneous-require': 'error', - 'n/no-hide-core-modules': 'error', - 'n/no-missing-import': 'off', // not compatible with typescript - 'n/no-missing-require': 'error', - 'n/no-new-require': 'error', - 'n/no-path-concat': 'error', - 'n/no-process-exit': 'error', - 'n/no-unpublished-bin': 'error', - 'n/no-unpublished-import': 'off', // TODO need to exclude seeds - 'n/no-unpublished-require': 'error', - 'n/no-unsupported-features': ['error', { ignores: ['modules'] }], - 'n/no-unsupported-features/es-builtins': 'error', - 'n/no-unsupported-features/es-syntax': 'error', - 'n/no-unsupported-features/node-builtins': 'error', - 'n/process-exit-as-throw': 'error', - 'n/shebang': 'error', - 'n/callback-return': 'error', - 'n/exports-style': 'error', - 'n/file-extension-in-import': 'off', - 'n/global-require': 'error', - 'n/no-mixed-requires': 'error', - 'n/no-process-env': 'error', - 'n/no-restricted-import': 'error', - 'n/no-restricted-require': 'error', - 'n/no-sync': 'error', - 'n/prefer-global/buffer': 'error', - 'n/prefer-global/console': 'error', - 'n/prefer-global/process': 'error', - 'n/prefer-global/text-decoder': 'error', - 'n/prefer-global/text-encoder': 'error', - 'n/prefer-global/url': 'error', - 'n/prefer-global/url-search-params': 'error', - 'n/prefer-promises/dns': 'error', - 'n/prefer-promises/fs': 'error', - // promise - // 'promise/catch-or-return': 'error', - // 'promise/no-return-wrap': 'error', - // 'promise/param-names': 'error', - // 'promise/always-return': 'error', - // 'promise/no-native': 'off', - // 'promise/no-nesting': 'warn', - // 'promise/no-promise-in-callback': 'warn', - // 'promise/no-callback-in-promise': 'warn', - // 'promise/avoid-new': 'warn', - // 'promise/no-new-statics': 'error', - // 'promise/no-return-in-finally': 'warn', - // 'promise/valid-params': 'warn', - // 'promise/prefer-await-to-callbacks': 'error', - // 'promise/no-multiple-resolved': 'error', - // eslint comments - '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], - '@eslint-community/eslint-comments/no-restricted-disable': 'error', - '@eslint-community/eslint-comments/no-use': 'off', - '@eslint-community/eslint-comments/require-description': 'off', - }, - overrides: [ - // only for ts files - { - files: ['*.ts', '*.tsx'], - extends: [ - 'plugin:@typescript-eslint/recommended', - // 'plugin:@typescript-eslint/recommended-requiring-type-checking', - // 'plugin:@typescript-eslint/strict', - ], - rules: { - // allow explicitly defined dangling promises - // '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], - 'no-void': ['error', { allowAsStatement: true }], - // ignore prefer-regexp-exec rule to allow string.match(regex) - '@typescript-eslint/prefer-regexp-exec': 'off', - // this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486 - 'import/unambiguous': 'off', - // this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - // this is to properly reference the referenced project database without requirement of compiling it - // eslint-disable-next-line camelcase - EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, - }, - }, - { - files: ['*.test.ts'], - plugins: ['jest'], - rules: { - 'jest/no-disabled-tests': 'error', - 'jest/no-focused-tests': 'error', - 'jest/no-identical-title': 'error', - 'jest/prefer-to-have-length': 'error', - 'jest/valid-expect': 'error', - '@typescript-eslint/unbound-method': 'off', - 'jest/unbound-method': 'error', - }, - }, - ], -} diff --git a/dlt-connector/.gitignore b/dlt-connector/.gitignore deleted file mode 100644 index 6eadcc884..000000000 --- a/dlt-connector/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/node_modules/ -/.env -/.env.bak -/build/ -package-json.lock -coverage -# emacs -*~ diff --git a/dlt-connector/.nvmrc b/dlt-connector/.nvmrc deleted file mode 100644 index 9dfdb2923..000000000 --- a/dlt-connector/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v19.5.0 \ No newline at end of file diff --git a/dlt-connector/.prettierrc.js b/dlt-connector/.prettierrc.js deleted file mode 100644 index bc1d767d7..000000000 --- a/dlt-connector/.prettierrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - semi: false, - printWidth: 100, - singleQuote: true, - trailingComma: "all", - tabWidth: 2, - bracketSpacing: true, - endOfLine: "auto", -}; diff --git a/dlt-connector/@types/bip32-ed25519/index.d.ts b/dlt-connector/@types/bip32-ed25519/index.d.ts deleted file mode 100644 index 7a3375ab6..000000000 --- a/dlt-connector/@types/bip32-ed25519/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'bip32-ed25519' diff --git a/dlt-connector/Dockerfile b/dlt-connector/Dockerfile deleted file mode 100644 index 3bdaf0679..000000000 --- a/dlt-connector/Dockerfile +++ /dev/null @@ -1,119 +0,0 @@ -################################################################################## -# BASE ########################################################################### -################################################################################## -FROM node:19.5.0-alpine3.17 as base -#FROM ubuntu:latest as base - -# ENVs (available in production aswell, can be overwritten by commandline or env file) -## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame -ENV DOCKER_WORKDIR="/app" -## We Cannot do `$(date -u +'%Y-%m-%dT%H:%M:%SZ')` here so we use unix timestamp=0 -ENV BUILD_DATE="1970-01-01T00:00:00.00Z" -## We cannot do $(npm run version).${BUILD_NUMBER} here so we default to 0.0.0.0 -ENV BUILD_VERSION="0.0.0.0" -## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000 -ENV BUILD_COMMIT="0000000" -## SET NODE_ENV -ENV NODE_ENV="production" -## App relevant Envs -ENV PORT="6010" - -# Labels -LABEL org.label-schema.build-date="${BUILD_DATE}" -LABEL org.label-schema.name="gradido:dlt-connector" -LABEL org.label-schema.description="Gradido dlt-connector" -LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md" -LABEL org.label-schema.url="https://gradido.net" -LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/dlt-connector" -LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}" -LABEL org.label-schema.vendor="Gradido Community" -LABEL org.label-schema.version="${BUILD_VERSION}" -LABEL org.label-schema.schema-version="1.0" -LABEL maintainer="support@gradido.net" - -# Install Additional Software -## install: @iota/client requirements -# Install Build Tool for Rust for @iota/client -RUN apk add --no-cache rust cargo python3 make g++ - -# Settings -## Expose Container Port -EXPOSE ${PORT} - -## Workdir -RUN mkdir -p ${DOCKER_WORKDIR} -WORKDIR ${DOCKER_WORKDIR} - -RUN mkdir -p /dlt-database - -################################################################################## -# DEVELOPMENT (Connected to the local environment, to reload on demand) ########## -################################################################################## -FROM base as development - -# We don't need to copy or build anything since we gonna bind to the -# local filesystem which will need a rebuild anyway - -# Run command -# (for development we need to execute yarn install since the -# node_modules are on another volume and need updating) -CMD /bin/sh -c "cd /dlt-database && yarn install && yarn build && cd /app && yarn install && yarn run dev" - -################################################################################## -# BUILD (Does contain all files and is therefore bloated) ######################## -################################################################################## -FROM base as build - -# Copy everything from dlt-connector -COPY ./dlt-connector/ ./ -# Copy everything from dlt-database -COPY ./dlt-database/ ../dlt-database/ - -# yarn install dlt-connector -RUN yarn install --production=false --frozen-lockfile --non-interactive - -# yarn install dlt-database -RUN cd ../dlt-database && yarn install --production=false --frozen-lockfile --non-interactive - -# yarn build -RUN yarn run build - -# yarn build dlt-database -RUN cd ../dlt-database && yarn run build - -################################################################################## -# TEST ########################################################################### -################################################################################## -FROM build as test - -# Run command -CMD /bin/sh -c "yarn run start" - -################################################################################## -# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) # -################################################################################## -FROM base as production - -# remove iota build tools to have production docker image smaller -RUN apk del rust cargo python3 make g++ - -# Copy "binary"-files from build image -COPY --from=build ${DOCKER_WORKDIR}/build ./build -COPY --from=build ${DOCKER_WORKDIR}/../dlt-database/build ../dlt-database/build -# We also copy the node_modules express and serve-static for the run script -COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules -COPY --from=build ${DOCKER_WORKDIR}/../dlt-database/node_modules ../dlt-database/node_modules -# Copy static files -# COPY --from=build ${DOCKER_WORKDIR}/public ./public -# Copy package.json for script definitions (lock file should not be needed) -COPY --from=build ${DOCKER_WORKDIR}/package.json ./package.json -# Copy tsconfig.json to provide alias path definitions -COPY --from=build ${DOCKER_WORKDIR}/tsconfig.json ./tsconfig.json -# Copy log4js-config.json to provide log configuration -COPY --from=build ${DOCKER_WORKDIR}/log4js-config.json ./log4js-config.json - -# Copy run scripts run/ -# COPY --from=build ${DOCKER_WORKDIR}/run ./run - -# Run command -CMD /bin/sh -c "yarn run start" diff --git a/dlt-connector/README.md b/dlt-connector/README.md new file mode 100644 index 000000000..d56e77437 --- /dev/null +++ b/dlt-connector/README.md @@ -0,0 +1 @@ +# Elysia with Bun runtime diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock new file mode 100644 index 000000000..80b8a8c7b --- /dev/null +++ b/dlt-connector/bun.lock @@ -0,0 +1,577 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "dlt-connector", + "dependencies": { + "@iota/client": "^2.2.4", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#217d03b", + }, + "devDependencies": { + "@biomejs/biome": "2.0.0", + "@elysiajs/trpc": "^1.1.0", + "@elysiajs/websocket": "^0.2.8", + "@trpc/server": "^11.4.3", + "@types/bun": "^1.2.17", + "dotenv": "^10.0.0", + "elysia": "^1.3.5", + "graphql-request": "^7.2.0", + "jose": "^5.2.2", + "jsonrpc-ts-client": "^0.2.3", + "log4js": "^6.9.1", + "typescript": "^5.8.3", + "uuid": "^8.3.2", + "valibot": "^1.1.0", + "zod": "^3.25.61", + }, + }, + }, + "trustedDependencies": [ + "@iota/client", + ], + "packages": { + "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + + "@elysiajs/trpc": ["@elysiajs/trpc@1.1.0", "", { "peerDependencies": { "elysia": ">= 1.1.0" } }, "sha512-M8QWC+Wa5Z5MWY/+uMQuwZ+JoQkp4jOc1ra4SncFy1zSjFGin59LO1AT0pE+DRJaFV17gha9y7cB6Q7GnaJEAw=="], + + "@elysiajs/websocket": ["@elysiajs/websocket@0.2.8", "", { "dependencies": { "nanoid": "^4.0.0", "raikiri": "^0.0.0-beta.3" }, "peerDependencies": { "elysia": ">= 0.2.2" } }, "sha512-K9KLmYL1SYuAV353GvmK0V9DG5w7XTOGsa1H1dGB5BUTzvBaMvnwNeqnJQ3cjf9V1c0EjQds0Ty4LfUFvV45jw=="], + + "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], + + "@iota/client": ["@iota/client@2.2.4", "", { "dependencies": { "neon-cli": "^0.8", "prebuild-install": "^6.1.2" } }, "sha512-6zjtqJgkSgrMUFLbxr9k+zXGnEVw6gjTFn5emN2nKpR78+mwW4jUXuNcy/M194bK4sLHjj0T0L4pRWJ6XTGaew=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.37", "", {}, "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw=="], + + "@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@trpc/server": ["@trpc/server@11.4.3", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-wnWq3wiLlMOlYkaIZz+qbuYA5udPTLS4GVVRyFkr6aT83xpdCHyVtURT+u4hSoIrOXQM9OPCNXSXsAujWZDdaw=="], + + "@types/bun": ["@types/bun@1.2.17", "", { "dependencies": { "bun-types": "1.2.17" } }, "sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q=="], + + "@types/node": ["@types/node@24.0.7", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw=="], + + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="], + + "are-we-there-yet": ["are-we-there-yet@1.1.7", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g=="], + + "array-back": ["array-back@3.1.0", "", {}, "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "axios": ["axios@0.24.0", "", { "dependencies": { "follow-redirects": "^1.14.4" } }, "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "builtins": ["builtins@1.0.3", "", {}, "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="], + + "bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], + + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "cli-width": ["cli-width@3.0.0", "", {}, "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "cmake-js": ["cmake-js@7.3.1", "", { "dependencies": { "axios": "^1.6.5", "debug": "^4", "fs-extra": "^11.2.0", "memory-stream": "^1.0.0", "node-api-headers": "^1.1.0", "npmlog": "^6.0.2", "rc": "^1.2.7", "semver": "^7.5.4", "tar": "^6.2.0", "url-join": "^4.0.1", "which": "^2.0.2", "yargs": "^17.7.2" }, "bin": { "cmake-js": "bin/cmake-js" } }, "sha512-aJtHDrTFl8qovjSSqXT9aC2jdGfmP8JQsPtjdLAXFfH1BF4/ImZ27Jx0R61TFg8Apc3pl6e2yBKMveAeRXx2Rw=="], + + "code-point-at": ["code-point-at@1.1.0", "", {}, "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "command-line-args": ["command-line-args@5.2.1", "", { "dependencies": { "array-back": "^3.1.0", "find-replace": "^3.0.0", "lodash.camelcase": "^4.3.0", "typical": "^4.0.0" } }, "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg=="], + + "command-line-commands": ["command-line-commands@3.0.2", "", { "dependencies": { "array-back": "^4.0.1" } }, "sha512-ac6PdCtdR6q7S3HN+JiVLIWGHY30PRYIEl2qPo+FuEuzwAUk0UYyimrngrg7FvF/mCr4Jgoqv5ZnHZgads50rw=="], + + "command-line-usage": ["command-line-usage@6.1.3", "", { "dependencies": { "array-back": "^4.0.2", "chalk": "^2.4.2", "table-layout": "^1.0.2", "typical": "^5.2.0" } }, "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw=="], + + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="], + + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], + + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "decompress-response": ["decompress-response@4.2.1", "", { "dependencies": { "mimic-response": "^2.0.0" } }, "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], + + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + + "dotenv": ["dotenv@10.0.0", "", {}, "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "elysia": ["elysia@1.3.5", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-XVIKXlKFwUT7Sta8GY+wO5reD9I0rqAEtaz1Z71UgJb61csYt8Q3W9al8rtL5RgumuRR8e3DNdzlUN9GkC4KDw=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="], + + "execspawn": ["execspawn@1.0.1", "", { "dependencies": { "util-extend": "^1.0.1" } }, "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg=="], + + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + + "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], + + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], + + "file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="], + + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + + "find-replace": ["find-replace@3.0.0", "", { "dependencies": { "array-back": "^3.0.1" } }, "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], + + "form-data": ["form-data@4.0.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA=="], + + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + + "fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "gauge": ["gauge@2.7.4", "", { "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.0", "object-assign": "^4.1.0", "signal-exit": "^3.0.0", "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" } }, "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "git-config": ["git-config@0.0.7", "", { "dependencies": { "iniparser": "~1.0.5" } }, "sha512-LidZlYZXWzVjS+M3TEwhtYBaYwLeOZrXci1tBgqp/vDdZTBMl02atvwb6G35L64ibscYoPnxfbwwUS+VZAISLA=="], + + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#217d03b", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#cmake_js" } }, "gradido-gradido-blockchain-js-217d03b"], + + "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], + + "graphql-request": ["graphql-request@7.2.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A=="], + + "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "has-unicode": ["has-unicode@2.0.1", "", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "iniparser": ["iniparser@1.0.5", "", {}, "sha512-i40MWqgTU6h/70NtMsDVVDLjDYWwcIR1yIEVDPfxZIJno9z9L4s83p/V7vAu2i48Vj0gpByrkGFub7ko9XvPrw=="], + + "inquirer": ["inquirer@7.3.3", "", { "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" } }, "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "jsonrpc-ts-client": ["jsonrpc-ts-client@0.2.3", "", { "dependencies": { "axios": "^0.24.0", "debug": "^4.3.3" } }, "sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + + "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], + + "make-promises-safe": ["make-promises-safe@5.1.0", "", {}, "sha512-AfdZ49rtyhQR/6cqVKGoH7y4ql7XkS5HJI1lZm0/5N6CQosy1eYbBJ/qbhkKHzo17UH7M918Bysf6XB9f3kS1g=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "memory-stream": ["memory-stream@1.0.0", "", { "dependencies": { "readable-stream": "^3.4.0" } }, "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "mimic-response": ["mimic-response@2.1.0", "", {}, "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mute-stream": ["mute-stream@0.0.8", "", {}, "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="], + + "nan": ["nan@2.22.2", "", {}, "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ=="], + + "nanoid": ["nanoid@4.0.2", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw=="], + + "napi-build-utils": ["napi-build-utils@1.0.2", "", {}, "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="], + + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "neon-cli": ["neon-cli@0.8.3", "", { "dependencies": { "chalk": "^4.1.0", "command-line-args": "^5.1.1", "command-line-commands": "^3.0.1", "command-line-usage": "^6.1.0", "git-config": "0.0.7", "handlebars": "^4.7.6", "inquirer": "^7.3.3", "make-promises-safe": "^5.1.0", "rimraf": "^3.0.2", "semver": "^7.3.2", "toml": "^3.0.0", "ts-typed-json": "^0.3.2", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" }, "bin": { "neon": "bin/cli.js" } }, "sha512-I44MB8PD0AEyFr/b5icR4sX1tsjdkb2T2uWEStG4Uf5C/jzalZPn7eazbQrW6KDyXNd8bc+LVuOr1v6CGTa1KQ=="], + + "node-abi": ["node-abi@2.30.1", "", { "dependencies": { "semver": "^5.4.1" } }, "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w=="], + + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + + "node-api-headers": ["node-api-headers@1.5.0", "", {}, "sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ=="], + + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + + "npm-path": ["npm-path@2.0.4", "", { "dependencies": { "which": "^1.2.10" }, "bin": { "npm-path": "bin/npm-path" } }, "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw=="], + + "npm-run-path": ["npm-run-path@3.1.0", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg=="], + + "npm-which": ["npm-which@3.0.1", "", { "dependencies": { "commander": "^2.9.0", "npm-path": "^2.0.2", "which": "^1.2.10" }, "bin": { "npm-which": "bin/npm-which.js" } }, "sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A=="], + + "npmlog": ["npmlog@4.1.2", "", { "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", "gauge": "~2.7.3", "set-blocking": "~2.0.0" } }, "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg=="], + + "number-is-nan": ["number-is-nan@1.0.1", "", {}, "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "prebuild-install": ["prebuild-install@6.1.4", "", { "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^3.0.3", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ=="], + + "prebuildify": ["prebuildify@github:einhornimmond/prebuildify#91f4e76", { "dependencies": { "cmake-js": "^7.2.1", "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", "npm-run-path": "^3.1.0", "npm-which": "^3.0.1", "pump": "^3.0.0", "tar-fs": "^2.1.0" }, "bin": { "prebuildify": "./bin.js" } }, "einhornimmond-prebuildify-91f4e76"], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + + "raikiri": ["raikiri@0.0.0-beta.8", "", {}, "sha512-cH/yfvkiGkN8IBB2MkRHikpPurTnd2sMkQ/xtGpXrp3O76P4ppcWPb+86mJaBDzKaclLnSX+9NnT79D7ifH4/w=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "reduce-flatten": ["reduce-flatten@2.0.0", "", {}, "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], + + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "run-async": ["run-async@2.4.1", "", {}, "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="], + + "rxjs": ["rxjs@6.6.7", "", { "dependencies": { "tslib": "^1.9.0" } }, "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], + + "simple-get": ["simple-get@3.1.1", "", { "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.21", "", {}, "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg=="], + + "streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "strtok3": ["strtok3@10.3.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "table-layout": ["table-layout@1.0.2", "", { "dependencies": { "array-back": "^4.0.1", "deep-extend": "~0.6.0", "typical": "^5.2.0", "wordwrapjs": "^4.0.0" } }, "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A=="], + + "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], + + "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + + "token-types": ["token-types@6.0.3", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-IKJ6EzuPPWtKtEIEPpIdXv9j5j2LGJEYk0CKY2efgKoYKLBiZdh6iQkLVBow/CB3phyWAWCyk+bZeaimJn6uRQ=="], + + "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], + + "ts-typed-json": ["ts-typed-json@0.3.2", "", {}, "sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA=="], + + "tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + + "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "typical": ["typical@4.0.0", "", {}, "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="], + + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + + "uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="], + + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "util-extend": ["util-extend@1.0.3", "", {}, "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA=="], + + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="], + + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + + "validate-npm-package-name": ["validate-npm-package-name@3.0.0", "", { "dependencies": { "builtins": "^1.0.3" } }, "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], + + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + + "wordwrapjs": ["wordwrapjs@4.0.1", "", { "dependencies": { "reduce-flatten": "^2.0.0", "typical": "^5.2.0" } }, "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="], + + "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "cmake-js/axios": ["axios@1.10.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw=="], + + "cmake-js/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], + + "cmake-js/npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], + + "command-line-commands/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], + + "command-line-usage/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], + + "command-line-usage/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "command-line-usage/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], + + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "gauge/string-width": ["string-width@1.0.2", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw=="], + + "gauge/strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="], + + "memory-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "node-abi/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "npm-path/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + + "npm-which/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + + "prebuildify/node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], + + "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "table-layout/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], + + "table-layout/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], + + "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "wordwrapjs/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], + + "bl/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "cmake-js/fs-extra/jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], + + "cmake-js/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "cmake-js/npmlog/are-we-there-yet": ["are-we-there-yet@3.0.1", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg=="], + + "cmake-js/npmlog/gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], + + "command-line-usage/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "command-line-usage/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "gauge/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@1.0.0", "", { "dependencies": { "number-is-nan": "^1.0.0" } }, "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw=="], + + "gauge/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], + + "memory-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "tar-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "cmake-js/npmlog/are-we-there-yet/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "command-line-usage/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "command-line-usage/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "cmake-js/npmlog/are-we-there-yet/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "command-line-usage/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + } +} diff --git a/dlt-connector/jest.config.js b/dlt-connector/jest.config.js deleted file mode 100644 index 652408b23..000000000 --- a/dlt-connector/jest.config.js +++ /dev/null @@ -1,37 +0,0 @@ -/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ -module.exports = { - verbose: true, - preset: 'ts-jest', - collectCoverage: true, - collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], - coverageThreshold: { - global: { - lines: 72, - }, - }, - setupFiles: ['/test/testSetup.ts'], - setupFilesAfterEnv: [], - modulePathIgnorePatterns: ['/build/'], - moduleNameMapper: { - '@/(.*)': '/src/$1', - '@arg/(.*)': '/src/graphql/arg/$1', - '@controller/(.*)': '/src/controller/$1', - '@enum/(.*)': '/src/graphql/enum/$1', - '@model/(.*)': '/src/graphql/model/$1', - '@resolver/(.*)': '/src/graphql/resolver/$1', - '@input/(.*)': '/src/graphql/input/$1', - '@proto/(.*)': '/src/proto/$1', - '@test/(.*)': '/test/$1', - '@client/(.*)': '/src/client/$1', - '@validator/(.*)': '/src/graphql/validator/$1', - }, -} -/* -@arg/*": ["src/graphql/arg/*"], - "@enum/*": ["src/graphql/enum/*"], - "@input/*": ["src/graphql/input/*"], - "@resolver/*": ["src/graphql/resolver/*"], - "@scalar/*": ["src/graphql/scalar/*"], - "@test/*": ["test/*"], - "@proto/*" : ["src/proto/*"], - */ diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 8b2f1b348..6d96cd326 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" }, "compress": true, "keepFileExt" : true, @@ -22,7 +22,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" }, "compress": true, "keepFileExt" : true, @@ -40,7 +40,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" } } }, diff --git a/dlt-connector/package.json b/dlt-connector/package.json index b2a4c194b..bb935e8c7 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -1,73 +1,42 @@ { - "name": "gradido-dlt-connector", - "version": "2.6.0", - "description": "Gradido DLT-Connector", - "main": "src/index.ts", - "repository": "https://github.com/gradido/gradido/", - "author": "Dario Rekowski", - "license": "Apache-2.0", - "private": false, + "name": "dlt-connector", + "version": "1.0.50", "scripts": { - "build": "tsc --build", - "clean": "tsc --build --clean", - "start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js", - "dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r dotenv/config -r tsconfig-paths/register src/index.ts", - "lint": "eslint --max-warnings=0 --ext .js,.ts .", - "test": "cross-env TZ=UTC NODE_ENV=development jest --forceExit --detectOpenHandles" + "start": "bun run src/index.ts", + "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --external=@iota/client", + "dev": "bun run --watch src/index.ts", + "test": "bun test", + "test:debug": "bun test --inspect-brk", + "typecheck": "tsc --noEmit", + "lint": "biome check --error-on-warnings .", + "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { - "@apollo/server": "^4.7.5", - "@apollo/utils.fetcher": "^3.0.0", - "@iota/client": "^2.2.4", - "body-parser": "^1.20.2", - "class-validator": "^0.14.0", - "cors": "^2.8.5", - "cross-env": "^7.0.3", - "dotenv": "10.0.0", - "express": "4.17.1", - "express-slow-down": "^2.0.1", - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#1c75576", - "graphql": "^16.7.1", - "graphql-request": "^6.1.0", - "graphql-scalars": "^1.22.2", - "helmet": "^7.1.0", - "jose": "^5.2.2", - "jsonrpc-ts-client": "^0.2.3", - "log4js": "^6.7.1", - "nodemon": "^2.0.20", - "reflect-metadata": "^0.1.13", - "tsconfig-paths": "^4.1.2", - "type-graphql": "^2.0.0-beta.2", - "uuid": "^9.0.1" + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#217d03b", + "@iota/client": "^2.2.4" }, "devDependencies": { - "@eslint-community/eslint-plugin-eslint-comments": "^3.2.1", - "@graphql-tools/mock": "^9.0.0", - "@types/cors": "^2.8.13", - "@types/jest": "^27.0.2", - "@types/node": "^18.11.18", - "@types/sodium-native": "^2.3.5", - "@types/uuid": "^8.3.4", - "@typescript-eslint/eslint-plugin": "^5.57.1", - "@typescript-eslint/parser": "^5.57.1", - "eslint": "^8.37.0", - "eslint-config-prettier": "^8.8.0", - "eslint-config-standard": "^17.0.0", - "eslint-import-resolver-typescript": "^3.5.4", - "eslint-plugin-dci-lint": "^0.3.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jest": "^27.2.1", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-security": "^1.7.1", - "jest": "^27.2.4", - "prettier": "^2.8.7", - "ts-jest": "^27.0.5", - "ts-node": "^10.9.1", - "typescript": "^4.9.4" + "@biomejs/biome": "2.0.0", + "@elysiajs/trpc": "^1.1.0", + "@elysiajs/websocket": "^0.2.8", + "@trpc/server": "^11.4.3", + "@types/bun": "^1.2.17", + "dotenv": "^10.0.0", + "elysia": "^1.3.5", + "graphql-request": "^7.2.0", + "jose": "^5.2.2", + "jsonrpc-ts-client": "^0.2.3", + "log4js": "^6.9.1", + "typescript": "^5.8.3", + "uuid": "^8.3.2", + "valibot": "^1.1.0", + "zod": "^3.25.61" }, "engines": { - "node": ">=14" - } + "node": ">=18" + }, + "module": "src/index.js", + "trustedDependencies": [ + "@iota/client" + ] } diff --git a/dlt-connector/schema.graphql b/dlt-connector/schema.graphql deleted file mode 100644 index 4ee07180d..000000000 --- a/dlt-connector/schema.graphql +++ /dev/null @@ -1,98 +0,0 @@ -# ----------------------------------------------- -# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!! -# !!! DO NOT MODIFY THIS FILE BY YOURSELF !!! -# ----------------------------------------------- - -type Community { - confirmedAt: String! - createdAt: String! - foreign: Boolean! - id: Int! - iotaTopic: String! - rootPublicKeyHex: String! -} - -input CommunityDraft { - createdAt: String! - foreign: Boolean! - uuid: String! -} - -"""The `Decimal` scalar type to represent currency values""" -scalar Decimal - -"""Type of the transaction""" -enum InputTransactionType { - CREATION - RECEIVE - SEND -} - -type Mutation { - addCommunity(data: CommunityDraft!): TransactionResult! - sendTransaction(data: TransactionDraft!): TransactionResult! -} - -type Query { - communities(confirmed: Boolean, foreign: Boolean, uuid: String): [Community!]! - community(confirmed: Boolean, foreign: Boolean, uuid: String): Community! - isCommunityExist(confirmed: Boolean, foreign: Boolean, uuid: String): Boolean! -} - -input TransactionDraft { - amount: Decimal! - backendTransactionId: Int! - createdAt: String! - recipientUser: UserIdentifier! - senderUser: UserIdentifier! - targetDate: String - type: InputTransactionType! -} - -type TransactionError { - message: String! - name: String! - type: TransactionErrorType! -} - -"""Transaction Error Type""" -enum TransactionErrorType { - ALREADY_EXIST - DB_ERROR - INVALID_SIGNATURE - LOGIC_ERROR - MISSING_PARAMETER - NOT_FOUND - NOT_IMPLEMENTED_YET - PROTO_DECODE_ERROR - PROTO_ENCODE_ERROR -} - -type TransactionRecipe { - createdAt: String! - id: Int! - topic: String! - type: TransactionType! -} - -type TransactionResult { - error: TransactionError - recipe: TransactionRecipe - succeed: Boolean! -} - -"""Type of the transaction""" -enum TransactionType { - COMMUNITY_ROOT - GRADIDO_CREATION - GRADIDO_DEFERRED_TRANSFER - GRADIDO_TRANSFER - GROUP_FRIENDS_UPDATE - REGISTER_ADDRESS -} - -input UserIdentifier { - accountNr: Int = 1 - communityUuid: String - uuid: String! -} \ No newline at end of file diff --git a/dlt-connector/src/manager/KeyPairCacheManager.ts b/dlt-connector/src/KeyPairCacheManager.ts similarity index 55% rename from dlt-connector/src/manager/KeyPairCacheManager.ts rename to dlt-connector/src/KeyPairCacheManager.ts index c3613f91d..b5501132c 100644 --- a/dlt-connector/src/manager/KeyPairCacheManager.ts +++ b/dlt-connector/src/KeyPairCacheManager.ts @@ -1,7 +1,8 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { logger } from '@/logging/logger' +import { KeyPairIdentifier } from './data/KeyPairIdentifier.logic' +import { getLogger, Logger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from './config/const' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -9,19 +10,19 @@ import { logger } from '@/logging/logger' * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. */ -// eslint-disable-next-line @typescript-eslint/no-extraneous-class export class KeyPairCacheManager { - // eslint-disable-next-line no-use-before-define private static instance: KeyPairCacheManager private cache: Map = new Map() - private homeCommunityUUID: string + private homeCommunityUUID: string | undefined + private logger: Logger /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. */ - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor() {} + private constructor() { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.KeyPairCacheManager`) + } /** * The static method that controls the access to the singleton instance. @@ -41,22 +42,34 @@ export class KeyPairCacheManager { } public getHomeCommunityUUID(): string { + if (!this.homeCommunityUUID) { + throw new Error('home community uuid is not set') + } return this.homeCommunityUUID } - public findKeyPair(input: KeyPairIdentifier): KeyPairEd25519 | undefined { - return this.cache.get(input.getKey()) + public findKeyPair(input: string): KeyPairEd25519 | undefined { + return this.cache.get(input) } - public addKeyPair(input: KeyPairIdentifier, keyPair: KeyPairEd25519): void { - const key = input.getKey() - if (this.cache.has(key)) { - logger.warn('key already exist, cannot add', { - key, + public addKeyPair(input: string, keyPair: KeyPairEd25519): void { + if (this.cache.has(input)) { + this.logger.warn('key already exist, cannot add', { + key: input, publicKey: keyPair.getPublicKey()?.convertToHex(), }) return } - this.cache.set(key, keyPair) + this.cache.set(input, keyPair) + } + + public async getKeyPair(input: string, createKeyPair: () => Promise): Promise { + const keyPair = this.cache.get(input) + if (!keyPair) { + const keyPair = await createKeyPair() + this.cache.set(input, keyPair) + return keyPair + } + return keyPair } } diff --git a/dlt-connector/src/client/BackendClient.ts b/dlt-connector/src/client/BackendClient.ts index 77356f5d8..4ee556f17 100644 --- a/dlt-connector/src/client/BackendClient.ts +++ b/dlt-connector/src/client/BackendClient.ts @@ -1,12 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { gql, GraphQLClient } from 'graphql-request' import { SignJWT } from 'jose' -import { CONFIG } from '@/config' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' +import { CONFIG } from '../config' +import { communitySchema, type Community } from '../schemas/rpcParameter.schema' +import { getLogger, Logger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import * as v from 'valibot' const homeCommunity = gql` query { @@ -17,30 +16,36 @@ const homeCommunity = gql` } } ` -interface Community { - homeCommunity: { - uuid: string - foreign: boolean - creationDate: string - } -} + // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts /** * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. */ -// eslint-disable-next-line @typescript-eslint/no-extraneous-class export class BackendClient { - // eslint-disable-next-line no-use-before-define private static instance: BackendClient client: GraphQLClient + logger: Logger + /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. */ - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor() {} + private constructor() { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.BackendClient`) + this.logger.addContext('url', CONFIG.BACKEND_SERVER_URL) + this.client = new GraphQLClient(CONFIG.BACKEND_SERVER_URL, { + headers: { + 'content-type': 'application/json', + }, + method: 'GET', + jsonSerializer: { + parse: JSON.parse, + stringify: JSON.stringify, + }, + }) + } /** * The static method that controls the access to the singleton instance. @@ -51,44 +56,29 @@ export class BackendClient { public static getInstance(): BackendClient | undefined { if (!BackendClient.instance) { BackendClient.instance = new BackendClient() - } - if (!BackendClient.instance.client) { - try { - BackendClient.instance.client = new GraphQLClient(CONFIG.BACKEND_SERVER_URL, { - headers: { - 'content-type': 'application/json', - }, - method: 'GET', - jsonSerializer: { - parse: JSON.parse, - stringify: JSON.stringify, - }, - }) - } catch (e) { - logger.error("couldn't connect to backend: ", e) - return - } - } + } return BackendClient.instance } - public async getHomeCommunityDraft(): Promise { - logger.info('check home community on backend') - const { data, errors } = await this.client.rawRequest( + public async getHomeCommunityDraft(): Promise { + this.logger.info('check home community on backend') + const { data, errors } = await this.client.rawRequest<{ homeCommunity: Community }>( homeCommunity, - {}, - { - authorization: 'Bearer ' + (await this.createJWTToken()), - }, + {}, // empty variables + await this.getRequestHeader(), ) if (errors) { - throw new LogError('error getting home community from backend', errors) + throw errors[0] + } + return v.parse(communitySchema, data.homeCommunity) + } + + private async getRequestHeader(): Promise<{ + authorization: string + }> { + return { + authorization: 'Bearer ' + (await this.createJWTToken()), } - const communityDraft = new CommunityDraft() - communityDraft.uuid = data.homeCommunity.uuid - communityDraft.foreign = data.homeCommunity.foreign - communityDraft.createdAt = data.homeCommunity.creationDate - return communityDraft } private async createJWTToken(): Promise { diff --git a/dlt-connector/src/client/GradidoNode.ts b/dlt-connector/src/client/GradidoNode.ts deleted file mode 100644 index 9e47ead87..000000000 --- a/dlt-connector/src/client/GradidoNode.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable camelcase */ -import { AddressType, ConfirmedTransaction, MemoryBlock, stringToAddressType } from 'gradido-blockchain-js' -import JsonRpcClient from 'jsonrpc-ts-client' -import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' - -import { CONFIG } from '@/config' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' -import { confirmedTransactionFromBase64 } from '@/utils/typeConverter' - -const client = new JsonRpcClient({ - url: CONFIG.NODE_SERVER_URL, -}) -/* -enum JsonRPCErrorCodes { - NONE = 0, - GRADIDO_NODE_ERROR = -10000, - UNKNOWN_GROUP = -10001, - NOT_IMPLEMENTED = -10002, - TRANSACTION_NOT_FOUND = -10003, - // default errors from json rpc standard: https://www.jsonrpc.org/specification - // -32700 Parse error Invalid JSON was received by the server. - PARSE_ERROR = -32700, - // -32600 Invalid Request The JSON sent is not a valid Request object. - INVALID_REQUEST = -32600, - // -32601 Method not found The method does not exist / is not available. - METHODE_NOT_FOUND = -32601, - // -32602 Invalid params Invalid method parameter(s). - INVALID_PARAMS = -32602, - // -32603 Internal error Internal JSON - RPC error. - INTERNAL_ERROR = -32603, - // -32000 to -32099 Server error Reserved for implementation-defined server-errors. -} -*/ - -interface ConfirmedTransactionList { - transactions: string[] - timeUsed: string -} - -interface ConfirmedTransactionResponse { - transaction: string - timeUsed: string -} - -interface AddressTypeResult { - addressType: string -} - -function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { - if (response.isSuccess()) { - return onSuccess(response.result) - } else if (response.isError()) { - throw new LogError('error by json rpc request to gradido node server', response.error) - } - throw new LogError('no success and no error', response) -} - -async function getTransactions( - fromTransactionId: number, - maxResultCount: number, - iotaTopic: string, -): Promise { - const parameter = { - format: 'base64', - fromTransactionId, - maxResultCount, - communityId: iotaTopic, - } - logger.info('call getTransactions on Node Server via jsonrpc 2.0 with ', parameter) - const response = await client.exec('getTransactions', parameter) // sends payload {jsonrpc: '2.0', params: ...} - return resolveResponse(response, (result: ConfirmedTransactionList) => { - logger.debug('GradidoNode used time', result.timeUsed) - return result.transactions.map((transactionBase64) => - confirmedTransactionFromBase64(transactionBase64), - ) - }) -} - -async function getTransaction( - transactionId: number | Buffer, - iotaTopic: string, -): Promise { - logger.info('call gettransaction on Node Server via jsonrpc 2.0') - const response = await client.exec('gettransaction', { - format: 'base64', - communityId: iotaTopic, - transactionId: typeof transactionId === 'number' ? transactionId : undefined, - iotaMessageId: transactionId instanceof Buffer ? transactionId.toString('hex') : undefined, - }) - return resolveResponse(response, (result: ConfirmedTransactionResponse) => { - logger.debug('GradidoNode used time', result.timeUsed) - return result.transaction && result.transaction !== '' - ? confirmedTransactionFromBase64(result.transaction) - : undefined - }) -} - -async function getLastTransaction(iotaTopic: string): Promise { - logger.info('call getlasttransaction on Node Server via jsonrpc 2.0') - const response = await client.exec('getlasttransaction', { - format: 'base64', - communityId: iotaTopic, - }) - return resolveResponse(response, (result: ConfirmedTransactionResponse) => { - logger.debug('GradidoNode used time', result.timeUsed) - return result.transaction && result.transaction !== '' - ? confirmedTransactionFromBase64(result.transaction) - : undefined - }) -} - -async function getAddressType(pubkey: Buffer, iotaTopic: string): Promise { - logger.info('call getaddresstype on Node Server via jsonrpc 2.0') - const response = await client.exec('getaddresstype', { - pubkey: pubkey.toString('hex'), - communityId: iotaTopic, - }) - return resolveResponse(response, (result: AddressTypeResult) => - stringToAddressType(result.addressType), - ) -} - -async function getTransactionsForAccount( - pubkey: MemoryBlock, - iotaTopic: string, - maxResultCount = 0, - firstTransactionNr = 1, -): Promise { - const parameter = { - pubkey: pubkey.convertToHex(), - format: 'base64', - firstTransactionNr, - maxResultCount, - communityId: iotaTopic, - } - logger.info('call listtransactionsforaddress on Node Server via jsonrpc 2.0', parameter) - const response = await client.exec( - 'listtransactionsforaddress', - parameter, - ) - return resolveResponse(response, (result: ConfirmedTransactionList) => { - logger.debug('GradidoNode used time', result.timeUsed) - return result.transactions.map((transactionBase64) => - confirmedTransactionFromBase64(transactionBase64), - ) - }) -} - -export { - getTransaction, - getLastTransaction, - getTransactions, - getAddressType, - getTransactionsForAccount, -} diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts new file mode 100644 index 000000000..27b4ad79e --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -0,0 +1,33 @@ +import * as v from 'valibot' +import { uuid4ToTopicSchema } from '../../schemas/typeConverter.schema' + +export enum TransactionFormatType { + BASE64 = 'base64', + JSON = 'json', +} + +export const transactionFormatTypeSchema = v.nullish( + v.enum(TransactionFormatType), + TransactionFormatType.BASE64 +) + +export type TransactionFormatTypeInput = v.InferInput + +export const getTransactionsInputSchema = v.object({ + format: transactionFormatTypeSchema, + // default value is 1, from first transactions + fromTransactionId: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1), + // default value is 100, max 100 transactions + maxResultCount: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100), + communityId: uuid4ToTopicSchema, +}) + +export type GetTransactionsInputType = v.InferInput + +export const getTransactionInputSchema = v.object({ + transactionIdentifier: v.object({ + iotaTopic: uuid4ToTopicSchema, + transactionNr: v.number(), + iotaMessageId: v.string(), + }), +}) \ No newline at end of file diff --git a/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts b/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts new file mode 100644 index 000000000..83a700b4d --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts @@ -0,0 +1,174 @@ +/* eslint-disable camelcase */ +import { AddressType, ConfirmedTransaction, MemoryBlock, stringToAddressType } from 'gradido-blockchain-js' +import JsonRpcClient from 'jsonrpc-ts-client' +import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' + +import { CONFIG } from '../../config' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import * as v from 'valibot' +import { confirmedTransactionFromBase64Schema } from '../../schemas/typeConverter.schema' +import { isPortOpenRetry } from '../../utils/network' +import { TransactionIdentifierInput, transactionIdentifierSchema } from '../../schemas/transaction.schema' +import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' +import { GetTransactionsInputType, TransactionFormatTypeInput, getTransactionsInputSchema, transactionFormatTypeSchema } from './input.schema' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) + +const client = new JsonRpcClient({ + url: CONFIG.NODE_SERVER_URL, +}) + + +interface ConfirmedTransactionList { + transactions: string[] + timeUsed: string +} + +interface ConfirmedTransactionResponse { + transaction: string + timeUsed: string +} + +interface AddressTypeResult { + addressType: string +} + +interface FindUserResponse { + pubkey: string + timeUsed: string +} + +export class GradidoNodeRequestError extends Error { + private response?: JsonRpcEitherResponse + constructor(message: string, response?: JsonRpcEitherResponse) { + super(message) + this.name = 'GradidoNodeRequestError' + this.response = response + } + getResponse(): JsonRpcEitherResponse | undefined { + return this.response + } +} + +function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { + if (response.isSuccess()) { + return onSuccess(response.result) + } else if (response.isError()) { + throw new GradidoNodeRequestError(response.error.message, response) + } + throw new GradidoNodeRequestError('no success and no error') +} + +async function getTransactions(input: GetTransactionsInputType): Promise { + const parameter = v.parse(getTransactionsInputSchema, input) + logger.debug('call getTransactions with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('getTransactions', parameter) + return resolveResponse(response, (result: ConfirmedTransactionList) => { + logger.info(`call getTransactions, used ${result.timeUsed}`) + return result.transactions.map((transactionBase64) => + v.parse(confirmedTransactionFromBase64Schema, transactionBase64), + ) + }) +} + +async function getTransaction( + transactionIdentifier: TransactionIdentifierInput, + format: TransactionFormatTypeInput +) +: Promise { + const parameter = { + ...v.parse(transactionIdentifierSchema, transactionIdentifier), + format: v.parse(transactionFormatTypeSchema, format), + } + logger.debug('call gettransaction with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('gettransaction', parameter) + return resolveResponse(response, (result: ConfirmedTransactionResponse) => { + logger.info(`call gettransaction, used ${result.timeUsed}`) + return result.transaction && result.transaction !== '' + ? v.parse(confirmedTransactionFromBase64Schema, result.transaction) + : undefined + }) +} + +async function getLastTransaction(iotaTopic: string): Promise { + const parameter = { + format: 'base64', + communityId: iotaTopic, + } + logger.debug('call getlasttransaction with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('getlasttransaction', parameter) + return resolveResponse(response, (result: ConfirmedTransactionResponse) => { + logger.info(`call getlasttransaction, used ${result.timeUsed}`) + return result.transaction && result.transaction !== '' + ? v.parse(confirmedTransactionFromBase64Schema, result.transaction) + : undefined + }) +} + +async function getAddressType(pubkey: Buffer, iotaTopic: string): Promise { + const parameter = { + pubkey: pubkey.toString('hex'), + communityId: iotaTopic, + } + logger.debug('call getaddresstype with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('getaddresstype', parameter) + return resolveResponse(response, (result: AddressTypeResult) => { + logger.info(`call getaddresstype`) + return stringToAddressType(result.addressType) + }) +} + +async function findUserByNameHash(nameHash: MemoryBlock, iotaTopic: string): Promise { + const parameter = { + nameHash: nameHash.convertToHex(), + communityId: iotaTopic, + } + logger.debug('call findUserByNameHash with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('findUserByNameHash', parameter) + if (response.isError() && response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND) { + return undefined + } + return resolveResponse(response, (result: FindUserResponse) => { + logger.info(`call findUserByNameHash, used ${result.timeUsed}`) + return result.pubkey && result.pubkey !== '' ? MemoryBlock.fromHex(result.pubkey) : undefined + }) +} + +async function getTransactionsForAccount( + pubkey: MemoryBlock, + iotaTopic: string, + maxResultCount = 0, + firstTransactionNr = 1, +): Promise { + const parameter = { + pubkey: pubkey.convertToHex(), + format: 'base64', + firstTransactionNr, + maxResultCount, + communityId: iotaTopic, + } + logger.debug('call listtransactionsforaddress with ', parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + const response = await client.exec('listtransactionsforaddress', parameter) + return resolveResponse(response, (result: ConfirmedTransactionList) => { + logger.info(`call listtransactionsforaddress, used ${result.timeUsed}`) + return result.transactions.map((transactionBase64) => + v.parse(confirmedTransactionFromBase64Schema, transactionBase64), + ) + }) +} + +export { + getTransaction, + getLastTransaction, + getTransactions, + getAddressType, + getTransactionsForAccount, + findUserByNameHash, +} diff --git a/dlt-connector/src/client/GradidoNode/output.schema.ts b/dlt-connector/src/client/GradidoNode/output.schema.ts new file mode 100644 index 000000000..e69de29bb diff --git a/dlt-connector/src/client/IotaClient.test.ts b/dlt-connector/src/client/IotaClient.test.ts deleted file mode 100644 index 5bee71b2e..000000000 --- a/dlt-connector/src/client/IotaClient.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ - -import { sendMessage, receiveMessage } from '@/client/IotaClient' - -jest.mock('@iota/client', () => { - const mockMessageSender = jest.fn().mockImplementation(() => { - return { - index: jest.fn().mockReturnThis(), - data: jest.fn().mockReturnThis(), - submit: jest - .fn() - .mockReturnValue('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710'), - } - }) - const mockMessageFinder = jest.fn().mockImplementation(() => { - return { - data: jest.fn().mockReturnValue({ - message: { - networkId: '1454675179895816119', - parentMessageIds: [ - '5f30efecca59fdfef7c103e85ef691b2b1dc474e9eae9056888a6d58605083e7', - '77cef2fb405daedcd7469e009bb87a6d9a4840e618cdb599cd21a30a9fec88dc', - '7d2cfb39f40585ba568a29ad7e85c1478b2584496eb736d4001ac344f6a6cacf', - 'c66da602874220dfa26925f6be540d37c0084d37cd04726fcc5be9d80b36f850', - ], - payload: { - type: 2, - index: '4752414449444f3a205465737448656c6c6f57656c7431', - data: '48656c6c6f20576f726c64202d20546875204a756e20303820323032332031343a35393a343520474d542b3030303020284b6f6f7264696e69657274652057656c747a65697429', - }, - nonce: '13835058055282465157', - }, - messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', - }), - } - }) - - const mockClient = { - message: mockMessageSender, - getMessage: mockMessageFinder, - } - const mockClientBuilder = { - node: jest.fn().mockReturnThis(), - build: jest.fn(() => mockClient), - } - return { - ClientBuilder: jest.fn(() => mockClientBuilder), - } -}) - -describe('Iota Tests', () => { - it('test mocked sendDataMessage', async () => { - const result = await sendMessage('Test Message', 'topic') - expect(result).toBe('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710') - }) - - it('should mock getMessage', async () => { - const result = await receiveMessage( - '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', - ) - expect(result).toMatchObject({ - message: { - payload: { - data: '48656c6c6f20576f726c64202d20546875204a756e20303820323032332031343a35393a343520474d542b3030303020284b6f6f7264696e69657274652057656c747a65697429', - index: '4752414449444f3a205465737448656c6c6f57656c7431', - }, - }, - messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', - }) - }) -}) diff --git a/dlt-connector/src/client/IotaClient.ts b/dlt-connector/src/client/IotaClient.ts deleted file mode 100644 index 3f2d318fa..000000000 --- a/dlt-connector/src/client/IotaClient.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ClientBuilder } from '@iota/client' -import { MessageWrapper } from '@iota/client/lib/types' - -import { CONFIG } from '@/config' -const client = new ClientBuilder().node(CONFIG.IOTA_API_URL).build() - -/** - * send data message onto iota tangle - * @param {string | Uint8Array} message - the message as utf based string, will be converted to hex automatically from @iota/client - * @param {string | Uint8Array} topic - the iota topic to which the message will be sended - * @return {Promise} the iota message typed - */ -function sendMessage( - message: string | Uint8Array, - topic: string | Uint8Array, -): Promise { - return client.message().index(topic).data(message).submit() -} - -/** - * receive message for known message id from iota tangle - * @param {string} messageId - as hex string - * @return {Promise} the iota message typed - */ -function receiveMessage(messageId: string): Promise { - return client.getMessage().data(messageId) -} - -export { sendMessage, receiveMessage } - -/** - * example for message: -```json -{ - message: { - networkId: '1454675179895816119', - parentMessageIds: [ - '5f30efecca59fdfef7c103e85ef691b2b1dc474e9eae9056888a6d58605083e7', - '77cef2fb405daedcd7469e009bb87a6d9a4840e618cdb599cd21a30a9fec88dc', - '7d2cfb39f40585ba568a29ad7e85c1478b2584496eb736d4001ac344f6a6cacf', - 'c66da602874220dfa26925f6be540d37c0084d37cd04726fcc5be9d80b36f850' - ], - payload: { - type: 2, - index: '4752414449444f3a205465737448656c6c6f57656c7431', - data: '48656c6c6f20576f726c64202d20546875204a756e20303820323032332031343a35393a343520474d542b3030303020284b6f6f7264696e69657274652057656c747a65697429' - }, - nonce: '13835058055282465157' - }, - messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710' -} -``` - */ diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts new file mode 100644 index 000000000..14b5cf215 --- /dev/null +++ b/dlt-connector/src/config/const.ts @@ -0,0 +1 @@ +export const LOG4JS_BASE_CATEGORY = 'dlt' diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 806d3fd50..2d016eee2 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -2,65 +2,48 @@ import dotenv from 'dotenv' dotenv.config() -const constants = { +const logging = { LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', - CONFIG_VERSION: { - DEFAULT: 'DEFAULT', - EXPECTED: 'v7.2024-09-24', - CURRENT: '', - }, } const server = { - PRODUCTION: process.env.NODE_ENV === 'production' ?? false, - JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', -} - -const iota = { - IOTA_API_URL: process.env.IOTA_API_URL ?? 'https://chrysalis-nodes.iota.org', - IOTA_COMMUNITY_ALIAS: process.env.IOTA_COMMUNITY_ALIAS ?? 'GRADIDO: TestHelloWelt2', - IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED ?? null, -} - -const dltConnector = { + PRODUCTION: process.env.NODE_ENV === 'production', DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT ?? 6010, } -const nodeServer = { - NODE_SERVER_URL: process.env.NODE_SERVER_URL ?? 'http://localhost:8340', -} - -const gradidoBlockchain = { +const secrets = { + JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: process.env.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET ?? 'invalid', GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: process.env.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY ?? 'invalid', } -const backendServer = { - BACKEND_SERVER_URL: process.env.BACKEND_SERVER_URL ?? 'http://backend:4000', +const iota = { + IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED ?? null, } -// Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION ?? constants.CONFIG_VERSION.DEFAULT -if ( - ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( - constants.CONFIG_VERSION.CURRENT, - ) -) { - throw new Error( - `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, - ) +const apis = { + CONNECT_TIMEOUT_MS: process.env.CONNECT_TIMEOUT_MS + ? Number.parseInt(process.env.CONNECT_TIMEOUT_MS) + : 1000, + CONNECT_RETRY_COUNT: process.env.CONNECT_RETRY_COUNT + ? Number.parseInt(process.env.CONNECT_RETRY_COUNT) + : 15, + CONNECT_RETRY_DELAY_MS: process.env.CONNECT_RETRY_DELAY_MS + ? Number.parseInt(process.env.CONNECT_RETRY_DELAY_MS) + : 500, + IOTA_API_URL: process.env.IOTA_API_URL ?? 'https://chrysalis-nodes.iota.org', + NODE_SERVER_URL: process.env.NODE_SERVER_URL ?? 'http://127.0.0.1:8340', + BACKEND_SERVER_URL: process.env.BACKEND_SERVER_URL ?? 'http://127.0.0.1:4000', } export const CONFIG = { - ...constants, + ...logging, ...server, + ...secrets, ...iota, - ...dltConnector, - ...nodeServer, - ...gradidoBlockchain, - ...backendServer, + ...apis, } diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts new file mode 100644 index 000000000..b0bade47b --- /dev/null +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -0,0 +1,97 @@ +import { MemoryBlock } from 'gradido-blockchain-js' +import { IdentifierAccount, IdentifierAccountInput, identifierAccountSchema } from '../schemas/account.schema' +import { ParameterError } from '../errors' +import * as v from 'valibot' + +export class KeyPairIdentifierLogic { + public identifier: IdentifierAccount + public constructor(identifier: IdentifierAccountInput) { + // check if data structure is like expected and fill in defaults + this.identifier = v.parse(identifierAccountSchema, identifier) + } + + isCommunityKeyPair(): boolean { + return !this.identifier.seed && !this.identifier.account + } + + isSeedKeyPair(): boolean { + return this.identifier.seed !== undefined + } + + isUserKeyPair(): boolean { + return ( + this.identifier.seed === undefined && + this.identifier.account != undefined && + this.identifier.account.accountNr === 0 + ) + } + + isAccountKeyPair(): boolean { + return ( + this.identifier.seed === undefined && + this.identifier.account != undefined && + this.identifier.account.accountNr > 0 + ) + } + + getSeed(): string { + if (!this.identifier.seed) { + throw new Error('get seed called on non seed key pair identifier, please check first with isSeedKeyPair()') + } + return this.identifier.seed.seed + } + + getCommunityUuid(): string { + return this.identifier.communityUuid + } + + getUserUuid(): string { + if (!this.identifier.account) { + throw new Error( + 'get user uuid called on non user key pair identifier, please check first with isUserKeyPair() or isAccountKeyPair()' + ) + } + return this.identifier.account.userUuid + } + + getAccountNr(): number { + if (!this.identifier.account?.accountNr) { + throw new Error( + 'get account nr called on non account key pair identifier, please check first with isAccountKeyPair()' + ) + } + return this.identifier.account.accountNr + } + + getSeedKey(): string { return this.getSeed() } + getCommunityKey(): string { return this.getCommunityUuid() } + getCommunityUserKey(): string { + return this.createCommunityUserHash() + } + getCommunityUserAccountKey(): string { + return this.createCommunityUserHash() + this.getAccountNr().toString() + } + + getKey(): string { + if (this.isSeedKeyPair()) { + return this.getSeedKey() + } else if (this.isCommunityKeyPair()) { + return this.getCommunityKey() + } else if (this.isUserKeyPair()) { + return this.getCommunityUserKey() + } else if (this.isAccountKeyPair()) { + return this.getCommunityUserAccountKey() + } + throw new ParameterError('KeyPairIdentifier: unhandled input type') + } + + private createCommunityUserHash(): string { + if (!this.identifier.account?.userUuid || !this.identifier.communityUuid) { + throw new ParameterError('userUuid and/or communityUuid is undefined') + } + const resultHexString = + this.identifier.communityUuid.replace(/-/g, '') + + this.identifier.account.userUuid.replace(/-/g, '') + return MemoryBlock.fromHex(resultHexString).calculateHash().convertToHex() + } +} diff --git a/dlt-connector/src/data/KeyPairIdentifier.ts b/dlt-connector/src/data/KeyPairIdentifier.ts deleted file mode 100644 index 3a98c2e0e..000000000 --- a/dlt-connector/src/data/KeyPairIdentifier.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { LogError } from '@/server/LogError' -import { uuid4sToMemoryBlock } from '@/utils/typeConverter' - -export class KeyPairIdentifier { - // used for community key pair if it is only parameter or for user key pair - communityUuid?: string - // if set calculate key pair from seed, ignore all other parameter - seed?: string - // used for user key pair and account key pair, need also communityUuid - userUuid?: string - // used for account key pair, need also userUuid - accountNr?: number - - public constructor(input: UserIdentifier | string | undefined = undefined) { - if (input instanceof UserIdentifier) { - if (input.seed !== undefined) { - this.seed = input.seed.seed - } else { - this.communityUuid = input.communityUuid - this.userUuid = input.communityUser?.uuid - this.accountNr = input.communityUser?.accountNr - } - } else if (typeof input === 'string') { - this.communityUuid = input - } - } - - isCommunityKeyPair(): boolean { - return this.communityUuid !== undefined && this.userUuid === undefined - } - - isSeedKeyPair(): boolean { - return this.seed !== undefined - } - - isUserKeyPair(): boolean { - return ( - this.communityUuid !== undefined && - this.userUuid !== undefined && - this.accountNr === undefined - ) - } - - isAccountKeyPair(): boolean { - return ( - this.communityUuid !== undefined && - this.userUuid !== undefined && - this.accountNr !== undefined - ) - } - - getKey(): string { - if (this.seed && this.isSeedKeyPair()) { - return this.seed - } else if (this.communityUuid && this.isCommunityKeyPair()) { - return this.communityUuid - } - if (this.userUuid && this.communityUuid) { - const communityUserHash = uuid4sToMemoryBlock([this.userUuid, this.communityUuid]) - .calculateHash() - .convertToHex() - if (this.isUserKeyPair()) { - return communityUserHash - } - if (this.accountNr && this.isAccountKeyPair()) { - return communityUserHash + this.accountNr.toString() - } - } - throw new LogError('KeyPairIdentifier: unhandled input type', this) - } -} diff --git a/dlt-connector/src/graphql/enum/AccountType.ts b/dlt-connector/src/enum/AccountType.ts similarity index 77% rename from dlt-connector/src/graphql/enum/AccountType.ts rename to dlt-connector/src/enum/AccountType.ts index 810c89044..8d8e5fcc0 100644 --- a/dlt-connector/src/graphql/enum/AccountType.ts +++ b/dlt-connector/src/enum/AccountType.ts @@ -1,5 +1,3 @@ -import { registerEnumType } from 'type-graphql' - /** * enum for graphql * describe input account type in UserAccountDraft @@ -14,8 +12,3 @@ export enum AccountType { SUBACCOUNT = 'SUBACCOUNT', // no creations allowed CRYPTO_ACCOUNT = 'CRYPTO_ACCOUNT', // user control his keys, no creations } - -registerEnumType(AccountType, { - name: 'AccountType', // this one is mandatory - description: 'Type of account', // this one is optional -}) diff --git a/dlt-connector/src/enum/AddressType.ts b/dlt-connector/src/enum/AddressType.ts new file mode 100644 index 000000000..0e0d8bb30 --- /dev/null +++ b/dlt-connector/src/enum/AddressType.ts @@ -0,0 +1,19 @@ +import { + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, + AddressType_COMMUNITY_HUMAN, + AddressType_COMMUNITY_PROJECT, + AddressType_CRYPTO_ACCOUNT, + AddressType_NONE, + AddressType_SUBACCOUNT, +} from 'gradido-blockchain-js' + +export enum AddressType { + COMMUNITY_AUF = AddressType_COMMUNITY_AUF, + COMMUNITY_GMW = AddressType_COMMUNITY_GMW, + COMMUNITY_HUMAN = AddressType_COMMUNITY_HUMAN, + COMMUNITY_PROJECT = AddressType_COMMUNITY_PROJECT, + CRYPTO_ACCOUNT = AddressType_CRYPTO_ACCOUNT, + NONE = AddressType_NONE, + SUBACCOUNT = AddressType_SUBACCOUNT, +} \ No newline at end of file diff --git a/dlt-connector/src/enum/GradidoNodeErrorCodes.ts b/dlt-connector/src/enum/GradidoNodeErrorCodes.ts new file mode 100644 index 000000000..49153dc15 --- /dev/null +++ b/dlt-connector/src/enum/GradidoNodeErrorCodes.ts @@ -0,0 +1,20 @@ +export enum GradidoNodeErrorCodes { + NONE = 0, + GRADIDO_NODE_ERROR = -10000, + UNKNOWN_GROUP = -10001, + NOT_IMPLEMENTED = -10002, + TRANSACTION_NOT_FOUND = -10003, + JSON_RPC_ERROR_ADDRESS_NOT_FOUND = -10004, + // default errors from json rpc standard: https://www.jsonrpc.org/specification + // -32700 Parse error Invalid JSON was received by the server. + PARSE_ERROR = -32700, + // -32600 Invalid Request The JSON sent is not a valid Request object. + INVALID_REQUEST = -32600, + // -32601 Method not found The method does not exist / is not available. + METHODE_NOT_FOUND = -32601, + // -32602 Invalid params Invalid method parameter(s). + INVALID_PARAMS = -32602, + // -32603 Internal error Internal JSON - RPC error. + INTERNAL_ERROR = -32603, + // -32000 to -32099 Server error Reserved for implementation-defined server-errors. +} \ No newline at end of file diff --git a/dlt-connector/src/graphql/enum/InputTransactionType.ts b/dlt-connector/src/enum/InputTransactionType.ts similarity index 67% rename from dlt-connector/src/graphql/enum/InputTransactionType.ts rename to dlt-connector/src/enum/InputTransactionType.ts index f1b56823e..65c806afc 100755 --- a/dlt-connector/src/graphql/enum/InputTransactionType.ts +++ b/dlt-connector/src/enum/InputTransactionType.ts @@ -1,5 +1,3 @@ -import { registerEnumType } from 'type-graphql' - // enum for graphql but with int because it is the same in backend // for transaction type from backend export enum InputTransactionType { @@ -11,8 +9,3 @@ export enum InputTransactionType { GRADIDO_REDEEM_DEFERRED_TRANSFER = 'GRADIDO_REDEEM_DEFERRED_TRANSFER', COMMUNITY_ROOT = 'COMMUNITY_ROOT', } - -registerEnumType(InputTransactionType, { - name: 'InputTransactionType', // this one is mandatory - description: 'Type of the transaction', // this one is optional -}) diff --git a/dlt-connector/src/graphql/enum/TransactionErrorType.ts b/dlt-connector/src/enum/TransactionErrorType.ts similarity index 75% rename from dlt-connector/src/graphql/enum/TransactionErrorType.ts rename to dlt-connector/src/enum/TransactionErrorType.ts index f89df4afe..0da6ebb53 100644 --- a/dlt-connector/src/graphql/enum/TransactionErrorType.ts +++ b/dlt-connector/src/enum/TransactionErrorType.ts @@ -1,5 +1,3 @@ -import { registerEnumType } from 'type-graphql' - // enum for graphql // error groups for resolver answers export enum TransactionErrorType { @@ -15,8 +13,3 @@ export enum TransactionErrorType { NOT_FOUND = 'Not found', VALIDATION_ERROR = 'Validation Error', } - -registerEnumType(TransactionErrorType, { - name: 'TransactionErrorType', - description: 'Transaction Error Type', -}) diff --git a/dlt-connector/src/errors.ts b/dlt-connector/src/errors.ts new file mode 100644 index 000000000..73e6fd0f4 --- /dev/null +++ b/dlt-connector/src/errors.ts @@ -0,0 +1,43 @@ +import { TransactionIdentifier } from './schemas/transaction.schema' +import { IdentifierAccount } from './schemas/account.schema' + +export class GradidoNodeError extends Error { + constructor(message: string) { + super(message) + this.name = 'GradidoNodeError' + } +} + +export class GradidoNodeMissingTransactionError extends GradidoNodeError { + public transactionIdentifier?: TransactionIdentifier + constructor(message: string, transactionIdentifier?: TransactionIdentifier) { + super(message) + this.name = 'GradidoNodeMissingTransactionError' + this.transactionIdentifier = transactionIdentifier + } +} + +export class GradidoNodeMissingUserError extends GradidoNodeError { + public userIdentifier?: IdentifierAccount + constructor(message: string, userIdentifier?: IdentifierAccount) { + super(message) + this.name = 'GradidoNodeMissingUserError' + this.userIdentifier = userIdentifier + } +} + +export class GradidoNodeInvalidTransactionError extends GradidoNodeError { + public transactionIdentifier?: TransactionIdentifier + constructor(message: string, transactionIdentifier?: TransactionIdentifier) { + super(message) + this.name = 'GradidoNodeInvalidTransactionError' + this.transactionIdentifier = transactionIdentifier + } +} + +export class ParameterError extends Error { + constructor(message: string) { + super(message) + this.name = 'ParameterError' + } +} diff --git a/dlt-connector/src/graphql/arg/CommunityArg.ts b/dlt-connector/src/graphql/arg/CommunityArg.ts deleted file mode 100644 index 59f65943e..000000000 --- a/dlt-connector/src/graphql/arg/CommunityArg.ts +++ /dev/null @@ -1,19 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { IsBoolean, IsUUID } from 'class-validator' -import { ArgsType, Field } from 'type-graphql' - -@ArgsType() -export class CommunityArg { - @Field(() => String, { nullable: true }) - @IsUUID('4') - uuid?: string - - @Field(() => Boolean, { nullable: true }) - @IsBoolean() - foreign?: boolean - - @Field(() => Boolean, { nullable: true }) - @IsBoolean() - confirmed?: boolean -} diff --git a/dlt-connector/src/graphql/const.ts b/dlt-connector/src/graphql/const.ts deleted file mode 100644 index ce7186a54..000000000 --- a/dlt-connector/src/graphql/const.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const MEMO_MAX_CHARS = 255 -export const MEMO_MIN_CHARS = 5 diff --git a/dlt-connector/src/graphql/input/CommunityDraft.ts b/dlt-connector/src/graphql/input/CommunityDraft.ts deleted file mode 100644 index 0b26e68d0..000000000 --- a/dlt-connector/src/graphql/input/CommunityDraft.ts +++ /dev/null @@ -1,20 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { isValidDateString } from '@validator/DateString' -import { IsBoolean, IsUUID } from 'class-validator' -import { Field, InputType } from 'type-graphql' - -@InputType() -export class CommunityDraft { - @Field(() => String) - @IsUUID('4') - uuid: string - - @Field(() => Boolean) - @IsBoolean() - foreign: boolean - - @Field(() => String) - @isValidDateString() - createdAt: string -} diff --git a/dlt-connector/src/graphql/input/CommunityUser.ts b/dlt-connector/src/graphql/input/CommunityUser.ts deleted file mode 100644 index 97eff7a76..000000000 --- a/dlt-connector/src/graphql/input/CommunityUser.ts +++ /dev/null @@ -1,15 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { IsPositive, IsUUID } from 'class-validator' -import { Field, Int, InputType } from 'type-graphql' - -@InputType() -export class CommunityUser { - @Field(() => String) - @IsUUID('4') - uuid: string - - @Field(() => Int, { defaultValue: 1, nullable: true }) - @IsPositive() - accountNr?: number -} diff --git a/dlt-connector/src/graphql/input/IdentifierSeed.ts b/dlt-connector/src/graphql/input/IdentifierSeed.ts deleted file mode 100644 index f09ad2f8b..000000000 --- a/dlt-connector/src/graphql/input/IdentifierSeed.ts +++ /dev/null @@ -1,15 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { IsString } from 'class-validator' -import { Field, InputType } from 'type-graphql' - -@InputType() -export class IdentifierSeed { - @Field(() => String) - @IsString() - seed: string - - constructor(seed: string) { - this.seed = seed - } -} diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts deleted file mode 100755 index 0306d70e0..000000000 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ /dev/null @@ -1,58 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs -import { InputTransactionType } from '@enum/InputTransactionType' -import { isValidDateString, isValidNumberString } from '@validator/DateString' -import { IsEnum, IsObject, IsPositive, MaxLength, MinLength, ValidateNested } from 'class-validator' -import { InputType, Field } from 'type-graphql' - -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from '@/graphql//const' -import { AccountType } from '@/graphql/enum/AccountType' - -import { UserIdentifier } from './UserIdentifier' - -@InputType() -export class TransactionDraft { - @Field(() => UserIdentifier) - @IsObject() - @ValidateNested() - user: UserIdentifier - - // not used for simply register address - @Field(() => UserIdentifier, { nullable: true }) - @IsObject() - @ValidateNested() - linkedUser?: UserIdentifier - - // not used for register address - @Field(() => String, { nullable: true }) - @isValidNumberString() - amount?: string - - @Field(() => String, { nullable: true }) - @MaxLength(MEMO_MAX_CHARS) - @MinLength(MEMO_MIN_CHARS) - memo?: string - - @Field(() => InputTransactionType) - @IsEnum(InputTransactionType) - type: InputTransactionType - - @Field(() => String) - @isValidDateString() - createdAt: string - - // only for creation transactions - @Field(() => String, { nullable: true }) - @isValidDateString() - targetDate?: string - - // only for deferred transaction - // duration in seconds - @Field(() => Number, { nullable: true }) - @IsPositive() - timeoutDuration?: number - - // only for register address - @Field(() => AccountType, { nullable: true }) - @IsEnum(AccountType) - accountType?: AccountType -} diff --git a/dlt-connector/src/graphql/input/UserIdentifier.ts b/dlt-connector/src/graphql/input/UserIdentifier.ts deleted file mode 100644 index f622c24e4..000000000 --- a/dlt-connector/src/graphql/input/UserIdentifier.ts +++ /dev/null @@ -1,24 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -import { IsObject, IsUUID, ValidateNested } from 'class-validator' -import { Field, InputType } from 'type-graphql' - -import { CommunityUser } from './CommunityUser' -import { IdentifierSeed } from './IdentifierSeed' - -@InputType() -export class UserIdentifier { - @Field(() => String) - @IsUUID('4') - communityUuid: string - - @Field(() => CommunityUser, { nullable: true }) - @IsObject() - @ValidateNested() - communityUser?: CommunityUser - - @Field(() => IdentifierSeed, { nullable: true }) - @IsObject() - @ValidateNested() - seed?: IdentifierSeed -} diff --git a/dlt-connector/src/graphql/model/TransactionError.ts b/dlt-connector/src/graphql/model/TransactionError.ts deleted file mode 100644 index eee54e19c..000000000 --- a/dlt-connector/src/graphql/model/TransactionError.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ObjectType, Field } from 'type-graphql' - -import { TransactionErrorType } from '../enum/TransactionErrorType' - -@ObjectType() -export class TransactionError implements Error { - constructor(type: TransactionErrorType, message: string) { - this.type = type - this.message = message - this.name = type.toString() - } - - @Field(() => TransactionErrorType) - type: TransactionErrorType - - @Field(() => String) - message: string - - @Field(() => String) - name: string -} diff --git a/dlt-connector/src/graphql/model/TransactionRecipe.ts b/dlt-connector/src/graphql/model/TransactionRecipe.ts deleted file mode 100644 index eae7f1a6f..000000000 --- a/dlt-connector/src/graphql/model/TransactionRecipe.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { GradidoTransaction, MemoryBlock, transactionTypeToString } from 'gradido-blockchain-js' -import { Field, ObjectType } from 'type-graphql' - -import { LogError } from '@/server/LogError' - -@ObjectType() -export class TransactionRecipe { - public constructor(transaction: GradidoTransaction, messageId: MemoryBlock) { - const body = transaction.getTransactionBody() - if (!body) { - throw new LogError('invalid gradido transaction, cannot geht valid TransactionBody') - } - - this.createdAt = body.getCreatedAt().getDate().toString() - this.type = transactionTypeToString(body?.getTransactionType()) - this.messageIdHex = messageId.convertToHex() - } - - @Field(() => String) - createdAt: string - - @Field(() => String) - type: string - - @Field(() => String) - messageIdHex: string -} diff --git a/dlt-connector/src/graphql/model/TransactionResult.ts b/dlt-connector/src/graphql/model/TransactionResult.ts deleted file mode 100644 index 346920310..000000000 --- a/dlt-connector/src/graphql/model/TransactionResult.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ObjectType, Field } from 'type-graphql' - -import { TransactionError } from './TransactionError' -import { TransactionRecipe } from './TransactionRecipe' - -@ObjectType() -export class TransactionResult { - constructor(content?: TransactionError | TransactionRecipe) { - this.succeed = true - if (content instanceof TransactionError) { - this.error = content - this.succeed = false - } else if (content instanceof TransactionRecipe) { - this.recipe = content - } - } - - // the error if one happened - @Field(() => TransactionError, { nullable: true }) - error?: TransactionError - - // if no error happened, the message id of the iota transaction - @Field(() => TransactionRecipe, { nullable: true }) - recipe?: TransactionRecipe - - @Field(() => Boolean) - succeed: boolean -} diff --git a/dlt-connector/src/graphql/resolver/AccountsResolver.ts b/dlt-connector/src/graphql/resolver/AccountsResolver.ts deleted file mode 100644 index 3db0ac26b..000000000 --- a/dlt-connector/src/graphql/resolver/AccountsResolver.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable camelcase */ -import { AddressType_NONE } from 'gradido-blockchain-js' -import { Arg, Query, Resolver } from 'type-graphql' - -import { getAddressType } from '@/client/GradidoNode' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { KeyPairCalculation } from '@/interactions/keyPairCalculation/KeyPairCalculation.context' -import { logger } from '@/logging/logger' -import { uuid4ToHash } from '@/utils/typeConverter' - -import { TransactionErrorType } from '../enum/TransactionErrorType' -import { UserIdentifier } from '../input/UserIdentifier' -import { TransactionError } from '../model/TransactionError' -import { TransactionResult } from '../model/TransactionResult' - -@Resolver() -export class AccountResolver { - @Query(() => Boolean) - async isAccountExist(@Arg('data') userIdentifier: UserIdentifier): Promise { - const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifier(userIdentifier)) - const publicKey = accountKeyPair.getPublicKey() - if (!publicKey) { - throw new TransactionResult( - new TransactionError(TransactionErrorType.NOT_FOUND, 'cannot get user public key'), - ) - } - - // ask gradido node server for account type, if type !== NONE account exist - const addressType = await getAddressType( - publicKey.data(), - uuid4ToHash(userIdentifier.communityUuid).convertToHex(), - ) - logger.info('isAccountExist', userIdentifier) - return addressType !== AddressType_NONE - } -} diff --git a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts b/dlt-connector/src/graphql/resolver/TransactionsResolver.ts deleted file mode 100755 index e7d1c105e..000000000 --- a/dlt-connector/src/graphql/resolver/TransactionsResolver.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Resolver, Arg, Mutation } from 'type-graphql' - -import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context' - -import { TransactionDraft } from '../input/TransactionDraft' -import { TransactionError } from '../model/TransactionError' -import { TransactionResult } from '../model/TransactionResult' - -@Resolver() -export class TransactionResolver { - @Mutation(() => TransactionResult) - async sendTransaction( - @Arg('data') - transactionDraft: TransactionDraft, - ): Promise { - try { - return await SendToIotaContext(transactionDraft) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error instanceof TransactionError) { - return new TransactionResult(error) - } else { - throw error - } - } - } -} diff --git a/dlt-connector/src/graphql/schema.ts b/dlt-connector/src/graphql/schema.ts deleted file mode 100755 index f0e2f7198..000000000 --- a/dlt-connector/src/graphql/schema.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GraphQLSchema } from 'graphql' -import { buildSchema } from 'type-graphql' - -import { AccountResolver } from './resolver/AccountsResolver' -import { TransactionResolver } from './resolver/TransactionsResolver' - -export const schema = async (): Promise => { - return buildSchema({ - resolvers: [TransactionResolver, AccountResolver], - validate: { - validationError: { target: false }, - skipMissingProperties: true, - skipNullProperties: true, - skipUndefinedProperties: false, - forbidUnknownValues: true, - stopAtFirstError: true, - }, - }) -} diff --git a/dlt-connector/src/graphql/validator/DateString.ts b/dlt-connector/src/graphql/validator/DateString.ts deleted file mode 100644 index 0445c1bbe..000000000 --- a/dlt-connector/src/graphql/validator/DateString.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { registerDecorator, ValidationOptions } from 'class-validator' - -export function isValidDateString(validationOptions?: ValidationOptions) { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (object: Object, propertyName: string) { - registerDecorator({ - name: 'isValidDateString', - target: object.constructor, - propertyName, - options: validationOptions, - validator: { - validate(value: string): boolean { - return !isNaN(Date.parse(value)) - }, - defaultMessage(): string { - return `${propertyName} must be a valid date string` - }, - }, - }) - } -} - -export function isValidNumberString(validationOptions?: ValidationOptions) { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (object: Object, propertyName: string) { - registerDecorator({ - name: 'isValidNumberString', - target: object.constructor, - propertyName, - options: validationOptions, - validator: { - validate(value: string): boolean { - return !isNaN(parseFloat(value)) - }, - defaultMessage(): string { - return `${propertyName} must be a valid number string` - }, - }, - }) - } -} diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index ac5366127..ce5ab8fb3 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,45 +1,22 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import 'reflect-metadata' - +import { Elysia } from 'elysia' +import { CONFIG } from './config' import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' - -import { CONFIG } from '@/config' - +import { getLogger, configure } from 'log4js' +import { readFileSync } from 'node:fs' +import { isPortOpenRetry } from './utils/network' import { BackendClient } from './client/BackendClient' -import { getTransaction } from './client/GradidoNode' -import { CommunityDraft } from './graphql/input/CommunityDraft' -import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' -import { logger } from './logging/logger' -import { KeyPairCacheManager } from './manager/KeyPairCacheManager' -import createServer from './server/createServer' -import { LogError } from './server/LogError' -import { uuid4ToHash } from './utils/typeConverter' - -async function waitForServer( - backend: BackendClient, - retryIntervalMs: number, - maxRetries: number, -): Promise { - let retries = 0 - while (retries < maxRetries) { - logger.info(`Attempt ${retries + 1} for connecting to backend`) - - try { - // Make a HEAD request to the server - return await backend.getHomeCommunityDraft() - } catch (error) { - logger.info('Server is not reachable: ', error) - } - - // Server is not reachable, wait and retry - await new Promise((resolve) => setTimeout(resolve, retryIntervalMs)) - retries++ - } - - throw new LogError('Max retries exceeded. Server did not become reachable.') -} +import { KeyPairCacheManager } from './KeyPairCacheManager' +import { communityUuidToTopicSchema } from './schemas/rpcParameter.schema' +import { parse } from 'valibot' +import { getTransaction } from './client/GradidoNode/jsonrpc.api' async function main() { + // configure log4js + // TODO: replace late by loader from config-schema + const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) + configure(options) + const logger = getLogger('dlt') + // TODO: replace with schema validation if (CONFIG.IOTA_HOME_COMMUNITY_SEED) { try { const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) @@ -47,62 +24,50 @@ async function main() { throw new Error('seed need to be greater than 32 Bytes') } } catch (error) { - throw new LogError( + logger.error( 'IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long', - error, ) + process.exit(1) } } + // load crypto keys for gradido blockchain lib loadCryptoKeys( MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY), ) - // eslint-disable-next-line no-console - console.log(`DLT_CONNECTOR_PORT=${CONFIG.DLT_CONNECTOR_PORT}`) - const { app } = await createServer() // ask backend for home community if we haven't one const backend = BackendClient.getInstance() if (!backend) { - throw new LogError('cannot create backend client') + throw new Error('cannot create backend client') } - // wait for backend server to be ready - await waitForServer(backend, 2500, 10) - - const communityDraft = await backend.getHomeCommunityDraft() - KeyPairCacheManager.getInstance().setHomeCommunityUUID(communityDraft.uuid) - logger.info('home community topic: %s', uuid4ToHash(communityDraft.uuid).convertToHex()) + // wait for backend server + await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) + const homeCommunity = await backend.getHomeCommunityDraft() + KeyPairCacheManager.getInstance().setHomeCommunityUUID(homeCommunity.uuid) + logger.info('home community topic: %s', parse(communityUuidToTopicSchema, homeCommunity.uuid)) logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) // ask gradido node if community blockchain was created try { - const firstTransaction = await getTransaction( - 1, - uuid4ToHash(communityDraft.uuid).convertToHex(), - ) - if (!firstTransaction) { + const topic = parse(communityUuidToTopicSchema, homeCommunity.uuid) + if (!await getTransaction(1, topic)) { // if not exist, create community root transaction - await SendToIotaContext(communityDraft) + await SendToIotaContext(homeCommunity) } } catch (e) { - // eslint-disable-next-line no-console - // console.log('error requesting gradido node: ', e) - // if not exist, create community root transaction - await SendToIotaContext(communityDraft) + logger.error('error requesting gradido node: ', e) } - app.listen(CONFIG.DLT_CONNECTOR_PORT, () => { - // eslint-disable-next-line no-console - console.log(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) - }) - - process.on('exit', () => { - // Add shutdown logic here. - }) + + const app = new Elysia() + .get('/', () => "Hello Elysia") + .listen(CONFIG.DLT_CONNECTOR_PORT, () => { + logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) + }) } main().catch((e) => { - // eslint-disable-next-line no-console + // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) - // eslint-disable-next-line n/no-process-exit process.exit(1) }) diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts index 1450d9cdb..0a4168f0d 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts @@ -1,5 +1,11 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' +import { communityUuidToTopicSchema } from '../../schemas/rpcParameter.schema' +import * as v from 'valibot' export abstract class AbstractRemoteKeyPairRole { + protected topic: string + public constructor(communityUuid: string) { + this.topic = v.parse(communityUuidToTopicSchema, communityUuid) + } public abstract retrieveKeyPair(): Promise } diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts index fb062b011..f4b25cd57 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -1,30 +1,43 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { getTransaction } from '@/client/GradidoNode' -import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' +import { getTransaction } from '../../client/GradidoNode/jsonrpc.api' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' +import { GradidoNodeInvalidTransactionError, GradidoNodeMissingTransactionError } from '../../errors' export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { - public constructor(private communityUuid: string) { - super() + public constructor(communityUuid: string) { + super(communityUuid) } public async retrieveKeyPair(): Promise { - const firstTransaction = await getTransaction(1, uuid4ToHash(this.communityUuid).convertToHex()) + const transactionIdentifier = { + transactionNr: 1, + iotaTopic: this.topic, + } + const firstTransaction = await getTransaction(transactionIdentifier) if (!firstTransaction) { - throw new LogError( - "GradidoNode Server don't know this community with uuid " + this.communityUuid, - ) + throw new GradidoNodeMissingTransactionError('Cannot find transaction', transactionIdentifier) } const transactionBody = firstTransaction.getGradidoTransaction()?.getTransactionBody() - if (!transactionBody || !transactionBody.isCommunityRoot()) { - throw new LogError('get invalid confirmed transaction from gradido node') + if (!transactionBody) { + throw new GradidoNodeInvalidTransactionError( + 'Invalid transaction, body is missing', + transactionIdentifier + ) + } + if (!transactionBody.isCommunityRoot()) { + throw new GradidoNodeInvalidTransactionError( + 'Invalid transaction, community root type expected', + transactionIdentifier + ) } const communityRoot = transactionBody.getCommunityRoot() if (!communityRoot) { - throw new LogError('invalid confirmed transaction') + throw new GradidoNodeInvalidTransactionError( + 'Invalid transaction, community root is missing', + transactionIdentifier + ) } return new KeyPairEd25519(communityRoot.getPublicKey()) } diff --git a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts index b888351cd..81b9a016c 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts @@ -1,21 +1,21 @@ import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' - +import { CONFIG } from '../../config' +import { ParameterError } from '../../errors' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class HomeCommunityKeyPairRole extends AbstractKeyPairRole { public generateKeyPair(): KeyPairEd25519 { + // TODO: prevent this check with valibot test on config if (!CONFIG.IOTA_HOME_COMMUNITY_SEED) { - throw new LogError( + throw new Error( 'IOTA_HOME_COMMUNITY_SEED is missing either in config or as environment variable', ) } const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) const keyPair = KeyPairEd25519.create(seed) if (!keyPair) { - throw new LogError("couldn't create keyPair from IOTA_HOME_COMMUNITY_SEED") + throw new ParameterError("couldn't create keyPair from IOTA_HOME_COMMUNITY_SEED") } return keyPair } diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index 0f9137453..c6164119c 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -1,10 +1,7 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' -import { LogError } from '@/server/LogError' - +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairCacheManager } from '../../KeyPairCacheManager' import { AccountKeyPairRole } from './AccountKeyPair.role' import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' @@ -16,61 +13,46 @@ import { UserKeyPairRole } from './UserKeyPair.role' * @DCI-Context * Context for calculating key pair for signing transactions */ -export async function KeyPairCalculation(input: KeyPairIdentifier): Promise { +export async function KeyPairCalculation(input: KeyPairIdentifierLogic): Promise { const cache = KeyPairCacheManager.getInstance() - - // Try cache lookup first - let keyPair = cache.findKeyPair(input) - if (keyPair) { - return keyPair - } - - const retrieveKeyPair = async (input: KeyPairIdentifier): Promise => { - if (input.isSeedKeyPair() && input.seed) { - return new LinkedTransactionKeyPairRole(input.seed).generateKeyPair() - } - if (!input.communityUuid) { - throw new LogError('missing community id') + return await cache.getKeyPair(input.getKey(), async () => { + if (input.isSeedKeyPair()) { + return new LinkedTransactionKeyPairRole(input.getSeed()).generateKeyPair() } // If input does not belong to the home community, handle as remote key pair - if (cache.getHomeCommunityUUID() !== input.communityUuid) { + if (cache.getHomeCommunityUUID() !== input.getCommunityUuid()) { const role = - input instanceof UserIdentifier - ? new RemoteAccountKeyPairRole(input) - : new ForeignCommunityKeyPairRole(input.communityUuid) + input.isAccountKeyPair() + ? new RemoteAccountKeyPairRole(input.identifier) + : new ForeignCommunityKeyPairRole(input.getCommunityUuid()) return await role.retrieveKeyPair() } - - let communityKeyPair = cache.findKeyPair(input) + const communityKeyPair = await cache.getKeyPair(input.getCommunityKey(), async () => { + return new HomeCommunityKeyPairRole().generateKeyPair() + }) if (!communityKeyPair) { - communityKeyPair = new HomeCommunityKeyPairRole().generateKeyPair() + throw new Error("couldn't generate community key pair") } if (input.isCommunityKeyPair()) { return communityKeyPair } - const userKeyPairIdentifier = new KeyPairIdentifier() - userKeyPairIdentifier.communityUuid = input.communityUuid - userKeyPairIdentifier.userUuid = input.userUuid - - let userKeyPair = cache.findKeyPair(userKeyPairIdentifier) - if (!userKeyPair && userKeyPairIdentifier.userUuid) { - userKeyPair = new UserKeyPairRole( - userKeyPairIdentifier.userUuid, + const userKeyPair = await cache.getKeyPair(input.getCommunityUserKey(), async () => { + return new UserKeyPairRole( + input.getUserUuid(), communityKeyPair, ).generateKeyPair() - } + }) if (!userKeyPair) { - throw new LogError("couldn't generate user key pair") + throw new Error("couldn't generate user key pair") } if (input.isUserKeyPair()) { return userKeyPair } - - const accountNr = input.accountNr ?? 1 - return new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() - } - - keyPair = await retrieveKeyPair(input) - cache.addKeyPair(input, keyPair) - return keyPair + const accountNr = input.getAccountNr() + const accountKeyPair = new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() + if (input.isAccountKeyPair()) { + return accountKeyPair + } + throw new Error("couldn't generate account key pair, unexpected type") + }) } diff --git a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts index 39a20dd7a..d31fd9814 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts @@ -1,8 +1,7 @@ import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { LogError } from '@/server/LogError' - import { AbstractKeyPairRole } from './AbstractKeyPair.role' +import { ParameterError } from '../../errors' export class LinkedTransactionKeyPairRole extends AbstractKeyPairRole { public constructor(private seed: string) { @@ -15,7 +14,7 @@ export class LinkedTransactionKeyPairRole extends AbstractKeyPairRole { const hash = new MemoryBlock(this.seed).calculateHash() const keyPair = KeyPairEd25519.create(hash) if (!keyPair) { - throw new LogError('error creating Ed25519 KeyPair from seed', this.seed) + throw new ParameterError(`error creating Ed25519 KeyPair from seed: ${this.seed.substring(0, 5)}...`) } return keyPair } diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts index 132e86499..6432366f4 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -1,39 +1,29 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { getTransactions } from '@/client/GradidoNode' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { LogError } from '@/server/LogError' -import { uuid4ToHash } from '@/utils/typeConverter' - +import { findUserByNameHash } from '../../client/GradidoNode/jsonrpc.api' +import { IdentifierAccount } from '../../schemas/account.schema' +import { GradidoNodeMissingUserError, ParameterError } from '../../errors' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' +import { uuid4ToHashSchema } from '../../schemas/typeConverter.schema' +import * as v from 'valibot' export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { - public constructor(private user: UserIdentifier) { - super() + public constructor(private identifier: IdentifierAccount) { + super(identifier.communityUuid) } public async retrieveKeyPair(): Promise { - if (!this.user.communityUser) { - throw new LogError('missing community user') + if (!this.identifier.account) { + throw new ParameterError('missing account') } - const nameHash = uuid4ToHash(this.user.communityUser.uuid) - const confirmedTransactions = await getTransactions( - 0, - 30, - uuid4ToHash(this.user.communityUuid).convertToHex(), + const accountPublicKey = await findUserByNameHash( + v.parse(uuid4ToHashSchema, this.identifier.account.userUuid), + this.topic, ) - for (let i = 0; i < confirmedTransactions.length; i++) { - const transactionBody = confirmedTransactions[i].getGradidoTransaction()?.getTransactionBody() - if (transactionBody && transactionBody.isRegisterAddress()) { - const registerAddress = transactionBody.getRegisterAddress() - if (registerAddress && registerAddress.getNameHash()?.equal(nameHash)) { - return new KeyPairEd25519(registerAddress.getAccountPublicKey()) - } - } + if (accountPublicKey) { + return new KeyPairEd25519(accountPublicKey) } - throw new LogError( - 'cannot find remote user in first 30 transaction from remote blockchain, please wait for better recover implementation', - ) + throw new GradidoNodeMissingUserError('cannot find remote user', this.identifier) } } diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts index ca724fc99..3762266b2 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -1,8 +1,6 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { hardenDerivationIndex } from '@/utils/derivationHelper' -import { uuid4ToBuffer } from '@/utils/typeConverter' - +import { hardenDerivationIndex } from '../../utils/derivationHelper' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class UserKeyPairRole extends AbstractKeyPairRole { @@ -14,7 +12,7 @@ export class UserKeyPairRole extends AbstractKeyPairRole { // example gradido id: 03857ac1-9cc2-483e-8a91-e5b10f5b8d16 => // wholeHex: '03857ac19cc2483e8a91e5b10f5b8d16'] - const wholeHex = uuid4ToBuffer(this.userUuid) + const wholeHex = Buffer.from(this.userUuid.replace(/-/g, ''), 'hex') const parts = [] for (let i = 0; i < 4; i++) { parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts index a1a7b237d..8771c6789 100644 --- a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts @@ -1,34 +1,37 @@ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { LogError } from '@/server/LogError' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { AUF_ACCOUNT_DERIVATION_INDEX, GMW_ACCOUNT_DERIVATION_INDEX, hardenDerivationIndex, -} from '@/utils/derivationHelper' +} from '../../utils/derivationHelper' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { Community, CommunityInput, communitySchema } from '../../schemas/rpcParameter.schema' +import * as v from 'valibot' export class CommunityRootTransactionRole extends AbstractTransactionRole { - constructor(private self: CommunityDraft) { + private com: Community + constructor(input: CommunityInput) { super() + this.com = v.parse(communitySchema, input) } getSenderCommunityUuid(): string { - return this.self.uuid + return this.com.uuid } getRecipientCommunityUuid(): string { - throw new LogError('cannot be used as cross group transaction') + throw new Error('cannot be used as cross group transaction') } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const communityKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.uuid)) + const communityKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic({ communityUuid: this.com.uuid })) const gmwKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), ) @@ -36,7 +39,7 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole { hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), ) builder - .setCreatedAt(new Date(this.self.createdAt)) + .setCreatedAt(this.com.createdAt) .setCommunityRoot( communityKeyPair.getPublicKey(), gmwKeyPair.getPublicKey(), diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index e3fa9a838..c930e1725 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -2,72 +2,80 @@ import { AuthenticatedEncryption, EncryptedMemo, GradidoTransactionBuilder, - GradidoUnit, TransferAmount, } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { KeyPairCacheManager } from '@/manager/KeyPairCacheManager' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { CreationTransactionInput, creationTransactionSchema, CreationTransaction } from '../../schemas/transaction.schema' +import { KeyPairCacheManager } from '../../KeyPairCacheManager' +import { TRPCError } from '@trpc/server' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - +import * as v from 'valibot' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { Uuidv4, uuidv4Schema } from '../../schemas/typeConverter.schema' export class CreationTransactionRole extends AbstractTransactionRole { - constructor(private self: TransactionDraft) { + private tx: CreationTransaction + private homeCommunityUuid: Uuidv4 + constructor(input: CreationTransactionInput) { super() + this.tx = v.parse(creationTransactionSchema, input) + this.homeCommunityUuid = v.parse( + uuidv4Schema, + KeyPairCacheManager.getInstance().getHomeCommunityUUID() + ) + if ( + this.homeCommunityUuid !== this.tx.user.communityUuid || + this.homeCommunityUuid !== this.tx.linkedUser.communityUuid + ) { + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'creation: both recipient and signer must belong to home community', + }) + } } getSenderCommunityUuid(): string { - return this.self.user.communityUuid + return this.tx.user.communityUuid } getRecipientCommunityUuid(): string { - throw new TransactionError( - TransactionErrorType.LOGIC_ERROR, - 'creation: cannot be used as cross group transaction', - ) + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'creation: cannot be used as cross group transaction', + }) } public async getGradidoTransactionBuilder(): Promise { - if (!this.self.targetDate) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'creation: target date missing', - ) - } - if (!this.self.linkedUser) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'creation: linked user missing', - ) - } - if (!this.self.amount) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'creation: amount missing') - } - if (!this.self.memo) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'creation: memo missing') - } - const builder = new GradidoTransactionBuilder() - const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) - const signerKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.linkedUser)) - const homeCommunityKeyPair = await KeyPairCalculation( - new KeyPairIdentifier(KeyPairCacheManager.getInstance().getHomeCommunityUUID()), + // Recipient: user (account owner) + const recipientKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.tx.user) ) - + // Signer: linkedUser (admin/moderator) + const signerKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.tx.linkedUser) + ) + const homeCommunityKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic({ + communityUuid: this.homeCommunityUuid + }), + ) + // Memo: encrypted, home community and recipient can decrypt it builder - .setCreatedAt(new Date(this.self.createdAt)) - .addMemo(new EncryptedMemo(this.self.memo, new AuthenticatedEncryption(homeCommunityKeyPair))) + .setCreatedAt(this.tx.createdAt) + .addMemo(new EncryptedMemo( + this.tx.memo, + new AuthenticatedEncryption(homeCommunityKeyPair), + new AuthenticatedEncryption(recipientKeyPair), + )) .setTransactionCreation( new TransferAmount( recipientKeyPair.getPublicKey(), - GradidoUnit.fromString(this.self.amount), + this.tx.amount, ), - new Date(this.self.targetDate), + this.tx.targetDate, ) .sign(signerKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 90783723e..655542537 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -1,72 +1,57 @@ import { AuthenticatedEncryption, - DurationSeconds, EncryptedMemo, GradidoTransactionBuilder, GradidoTransfer, - GradidoUnit, TransferAmount, } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' - +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { DeferredTransferTransactionInput, deferredTransferTransactionSchema, DeferredTransferTransaction } from '../../schemas/transaction.schema' +import * as v from 'valibot' +import { TRPCError } from '@trpc/server' +import { identifierSeedSchema, IdentifierSeed } from '../../schemas/account.schema' export class DeferredTransferTransactionRole extends AbstractTransactionRole { - constructor(protected self: TransactionDraft) { + private tx: DeferredTransferTransaction + private seed: IdentifierSeed + constructor(protected input: DeferredTransferTransactionInput) { super() + this.tx = v.parse(deferredTransferTransactionSchema, input) + this.seed = v.parse(identifierSeedSchema, input.linkedUser.seed) } getSenderCommunityUuid(): string { - return this.self.user.communityUuid + return this.tx.user.communityUuid } getRecipientCommunityUuid(): string { - throw new TransactionError( - TransactionErrorType.LOGIC_ERROR, - 'deferred transfer: cannot be used as cross group transaction', - ) + throw new TRPCError({ + code: 'NOT_IMPLEMENTED', + message: 'deferred transfer: cannot be used as cross group transaction yet', + }) } public async getGradidoTransactionBuilder(): Promise { - if (!this.self.linkedUser || !this.self.linkedUser.seed) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: missing linked user or not a seed', - ) - } - if (!this.self.amount) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: amount missing', - ) - } - if (!this.self.memo) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: memo missing', - ) - } - if (!this.self.timeoutDuration) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: timeout duration missing', - ) - } const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) - const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.linkedUser)) + const senderKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.tx.user) + ) + const recipientKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic({ + communityUuid: this.tx.linkedUser.communityUuid, + seed: this.seed, + }) + ) builder - .setCreatedAt(new Date(this.self.createdAt)) + .setCreatedAt(this.tx.createdAt) .addMemo( new EncryptedMemo( - this.self.memo, + this.tx.memo, new AuthenticatedEncryption(senderKeyPair), new AuthenticatedEncryption(recipientKeyPair), ), @@ -75,13 +60,13 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), - GradidoUnit.fromString(this.self.amount).calculateCompoundInterest( - this.self.timeoutDuration, + this.tx.amount.calculateCompoundInterest( + this.tx.timeoutDuration.getSeconds(), ), ), recipientKeyPair.getPublicKey(), ), - new DurationSeconds(this.self.timeoutDuration), + this.tx.timeoutDuration, ) .sign(senderKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts index 70d612e08..a664a34c0 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -1,60 +1,69 @@ /* eslint-disable camelcase */ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { LogError } from '@/server/LogError' -import { accountTypeToAddressType, uuid4ToHash } from '@/utils/typeConverter' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' +import { RegisterAddressTransactionInput, registerAddressTransactionSchema, RegisterAddressTransaction } from '../../schemas/transaction.schema' +import { IdentifierAccount, IdentifierCommunityAccount, identifierCommunityAccountSchema } from '../../schemas/account.schema' +import * as v from 'valibot' +import { TRPCError } from '@trpc/server' +import { uuid4ToHashSchema } from '../../schemas/typeConverter.schema' export class RegisterAddressTransactionRole extends AbstractTransactionRole { - constructor(private self: TransactionDraft) { + private tx: RegisterAddressTransaction + private account: IdentifierCommunityAccount + constructor(input: RegisterAddressTransactionInput) { super() + this.tx = v.parse(registerAddressTransactionSchema, input) + this.account = v.parse(identifierCommunityAccountSchema, input.user.account) } getSenderCommunityUuid(): string { - return this.self.user.communityUuid + return this.tx.user.communityUuid } getRecipientCommunityUuid(): string { - throw new LogError('cannot yet be used as cross group transaction') + throw new TRPCError({ + code: 'NOT_IMPLEMENTED', + message: 'register address: cannot be used as cross group transaction yet', + }) } public async getGradidoTransactionBuilder(): Promise { - if (!this.self.accountType) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'register address: account type missing', - ) - } - - if (!this.self.user.communityUser) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - "register address: user isn't a community user", - ) - } - const builder = new GradidoTransactionBuilder() const communityKeyPair = await KeyPairCalculation( - new KeyPairIdentifier(this.self.user.communityUuid), + new KeyPairIdentifierLogic({ communityUuid: this.tx.user.communityUuid }), ) - const keyPairIdentifer = new KeyPairIdentifier(this.self.user) - const accountKeyPair = await KeyPairCalculation(keyPairIdentifer) - // unsetting accountNr change identifier from account key pair to user key pair - keyPairIdentifer.accountNr = undefined - const userKeyPair = await KeyPairCalculation(keyPairIdentifer) + const userKeyPairIdentifier: IdentifierAccount = { + communityUuid: this.tx.user.communityUuid, + account: { + userUuid: this.account.userUuid, + accountNr: 0, + }, + } + const accountKeyPairIdentifier: IdentifierAccount = { + communityUuid: this.tx.user.communityUuid, + account: { + userUuid: this.account.userUuid, + accountNr: this.account.accountNr, + }, + } + const userKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(userKeyPairIdentifier) + ) + const accountKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(accountKeyPairIdentifier) + ) + builder - .setCreatedAt(new Date(this.self.createdAt)) + .setCreatedAt(this.tx.createdAt) .setRegisterAddress( userKeyPair.getPublicKey(), - accountTypeToAddressType(this.self.accountType), - uuid4ToHash(this.self.user.communityUser.uuid), + this.tx.accountType, + v.parse(uuid4ToHashSchema, this.account.userUuid), accountKeyPair.getPublicKey(), ) .sign(communityKeyPair) diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index dd730f590..344efeba5 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -2,76 +2,62 @@ import { AuthenticatedEncryption, EncryptedMemo, GradidoTransactionBuilder, - GradidoUnit, TransferAmount, } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { TransactionError } from '@/graphql/model/TransactionError' -import { uuid4ToHash } from '@/utils/typeConverter' - +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - import { AbstractTransactionRole } from './AbstractTransaction.role' +import { TransferTransactionInput, transferTransactionSchema, TransferTransaction } from '../../schemas/transaction.schema' +import * as v from 'valibot' +import { uuid4ToTopicSchema } from '../../schemas/typeConverter.schema' export class TransferTransactionRole extends AbstractTransactionRole { - private linkedUser: UserIdentifier - constructor(private self: TransactionDraft) { + private tx: TransferTransaction + constructor(input: TransferTransactionInput) { super() - if (!this.self.linkedUser) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'transfer: linked user missing', - ) - } - this.linkedUser = this.self.linkedUser + this.tx = v.parse(transferTransactionSchema, input) } getSenderCommunityUuid(): string { - return this.self.user.communityUuid + return this.tx.user.communityUuid } getRecipientCommunityUuid(): string { - return this.linkedUser.communityUuid + return this.tx.linkedUser.communityUuid } public async getGradidoTransactionBuilder(): Promise { - if (!this.self.amount) { - throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'transfer: amount missing') - } - if (!this.self.memo) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'deferred transfer: memo missing', - ) - } const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) - const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.linkedUser)) + // sender + signer + const senderKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.tx.user) + ) + // recipient + const recipientKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.tx.linkedUser) + ) builder - .setCreatedAt(new Date(this.self.createdAt)) + .setCreatedAt(new Date(this.tx.createdAt)) .addMemo( new EncryptedMemo( - this.self.memo, + this.tx.memo, new AuthenticatedEncryption(senderKeyPair), new AuthenticatedEncryption(recipientKeyPair), ), ) .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), GradidoUnit.fromString(this.self.amount)), + new TransferAmount(senderKeyPair.getPublicKey(), this.tx.amount), recipientKeyPair.getPublicKey(), ) - const senderCommunity = this.self.user.communityUuid - const recipientCommunity = this.linkedUser.communityUuid + const senderCommunity = this.tx.user.communityUuid + const recipientCommunity = this.tx.linkedUser.communityUuid if (senderCommunity !== recipientCommunity) { // we have a cross group transaction builder - .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) - .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) + .setSenderCommunity(v.parse(uuid4ToTopicSchema, senderCommunity)) + .setRecipientCommunity(v.parse(uuid4ToTopicSchema, recipientCommunity)) } builder.sign(senderKeyPair) return builder diff --git a/dlt-connector/src/logging/AbstractLogging.view.ts b/dlt-connector/src/logging/AbstractLogging.view.ts deleted file mode 100644 index ddb1cb6ed..000000000 --- a/dlt-connector/src/logging/AbstractLogging.view.ts +++ /dev/null @@ -1,38 +0,0 @@ -import util from 'util' - -import { Timestamp, TimestampSeconds } from 'gradido-blockchain-js' - -export abstract class AbstractLoggingView { - protected bufferStringFormat: BufferEncoding = 'hex' - - // This function gets called automatically when JSON.stringify() is called on this class instance - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public abstract toJSON(): any - public toString(): string { - return JSON.stringify(this.toJSON(), null, 2) - } - - // called form console.log or log4js logging functions - [util.inspect.custom](): string { - return this.toString() - } - - protected dateToString(date: Date | undefined | null): string | undefined { - if (date) { - return date.toISOString() - } - return undefined - } - - protected timestampSecondsToDateString(timestamp: TimestampSeconds): string | undefined { - if (timestamp && timestamp.getSeconds()) { - return timestamp.getDate().toISOString() - } - } - - protected timestampToDateString(timestamp: Timestamp): string | undefined { - if (timestamp && (timestamp.getSeconds() || timestamp.getNanos())) { - return timestamp.getDate().toISOString() - } - } -} diff --git a/dlt-connector/src/logging/CommunityUserLogging.view.ts b/dlt-connector/src/logging/CommunityUserLogging.view.ts deleted file mode 100644 index f1b421cd6..000000000 --- a/dlt-connector/src/logging/CommunityUserLogging.view.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CommunityUser } from '@/graphql/input/CommunityUser' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class CommunityUserLoggingView extends AbstractLoggingView { - public constructor(private self: CommunityUser) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - uuid: this.self.uuid, - accountNr: this.self.accountNr, - } - } -} diff --git a/dlt-connector/src/logging/IdentifierSeedLogging.view.ts b/dlt-connector/src/logging/IdentifierSeedLogging.view.ts deleted file mode 100644 index d34012e17..000000000 --- a/dlt-connector/src/logging/IdentifierSeedLogging.view.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { IdentifierSeed } from '@/graphql/input/IdentifierSeed' - -import { AbstractLoggingView } from './AbstractLogging.view' - -export class IdentifierSeedLoggingView extends AbstractLoggingView { - public constructor(private self: IdentifierSeed) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - seed: this.self.seed, - } - } -} diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts deleted file mode 100644 index 8f9e11331..000000000 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { getEnumValue } from '@/utils/typeConverter' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { UserIdentifierLoggingView } from './UserIdentifierLogging.view' - -export class TransactionDraftLoggingView extends AbstractLoggingView { - public constructor(private self: TransactionDraft) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - user: new UserIdentifierLoggingView(this.self.user).toJSON(), - linkedUser: - this.self.linkedUser instanceof UserIdentifier - ? new UserIdentifierLoggingView(this.self.linkedUser).toJSON() - : 'seed', - amount: Number(this.self.amount), - type: getEnumValue(InputTransactionType, this.self.type), - createdAt: this.self.createdAt, - targetDate: this.self.targetDate, - } - } -} diff --git a/dlt-connector/src/logging/UserIdentifierLogging.view.ts b/dlt-connector/src/logging/UserIdentifierLogging.view.ts deleted file mode 100644 index 16343551f..000000000 --- a/dlt-connector/src/logging/UserIdentifierLogging.view.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { UserIdentifier } from '@/graphql/input/UserIdentifier' - -import { AbstractLoggingView } from './AbstractLogging.view' -import { CommunityUserLoggingView } from './CommunityUserLogging.view' -import { IdentifierSeedLoggingView } from './IdentifierSeedLogging.view' - -export class UserIdentifierLoggingView extends AbstractLoggingView { - public constructor(private self: UserIdentifier) { - super() - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public toJSON(): any { - return { - communityUuid: this.self.communityUuid, - communityUser: this.self.communityUser - ? new CommunityUserLoggingView(this.self.communityUser).toJSON() - : undefined, - seed: this.self.seed ? new IdentifierSeedLoggingView(this.self.seed).toJSON() : undefined, - } - } -} diff --git a/dlt-connector/src/logging/logger.ts b/dlt-connector/src/logging/logger.ts deleted file mode 100644 index bec2ec578..000000000 --- a/dlt-connector/src/logging/logger.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { readFileSync } from 'fs' - -import log4js from 'log4js' - -import { CONFIG } from '@/config' - -const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) - -log4js.configure(options) - -const logger = log4js.getLogger('dlt') - -export { logger } diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts new file mode 100644 index 000000000..4242558b3 --- /dev/null +++ b/dlt-connector/src/schemas/account.schema.ts @@ -0,0 +1,40 @@ + +import * as v from 'valibot' +import { uuidv4Schema } from './typeConverter.schema' + +// use code from transaction links +export const identifierSeedSchema = v.object({ + seed: v.pipe( + v.string('expect string type'), + v.length(24, 'expect seed length 24') + ) +}) + +export type IdentifierSeed = v.InferOutput + +// identifier for gradido community accounts, inside a community +export const identifierCommunityAccountSchema = v.object({ + userUuid: uuidv4Schema, + accountNr: v.nullish(v.number('expect number type'), 0), +}) + +export type IdentifierCommunityAccount = v.InferOutput + +// identifier for gradido account, including the community uuid +export const identifierAccountSchema = v.pipe( + v.object({ + communityUuid: uuidv4Schema, + account: v.nullish(identifierCommunityAccountSchema, undefined), + seed: v.nullish(identifierSeedSchema, undefined), + }), + v.custom((value: any) => { + const setFieldsCount = Number(value.seed !== undefined) + Number(value.account !== undefined) + if (setFieldsCount !== 1) { + return false + } + return true + }, 'expect seed or account') +) + +export type IdentifierAccountInput = v.InferInput +export type IdentifierAccount = v.InferOutput diff --git a/dlt-connector/src/schemas/rpcParameter.schema.test.ts b/dlt-connector/src/schemas/rpcParameter.schema.test.ts new file mode 100644 index 000000000..8680c3958 --- /dev/null +++ b/dlt-connector/src/schemas/rpcParameter.schema.test.ts @@ -0,0 +1,21 @@ +import { communitySchema } from './rpcParameter.schema' +import { uuidv4Schema } from './typeGuard.schema' +import * as v from 'valibot' +// only for IDE, bun don't need this to work +import { describe, expect, it } from 'bun:test' + +describe('rpcParameter.schema', () => { + it('community', () => { + expect(v.parse(communitySchema, { + uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', + foreign: false, + createdAt: '2021-01-01', + })).toEqual( + { + uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), + foreign: false, + createdAt: new Date('2021-01-01'), + }, + ) + }) +}) diff --git a/dlt-connector/src/schemas/rpcParameter.schema.ts b/dlt-connector/src/schemas/rpcParameter.schema.ts new file mode 100644 index 000000000..0a05dd86c --- /dev/null +++ b/dlt-connector/src/schemas/rpcParameter.schema.ts @@ -0,0 +1,19 @@ +import * as v from 'valibot' +import { uuidv4Schema } from './typeGuard.schema' +import { dateSchema } from './typeConverter.schema' + +/** + * Schema Definitions for rpc call parameter, when dlt-connector is called from backend + */ + +/** + * Schema for community, for creating new CommunityRoot Transaction on gradido blockchain + */ +export const communitySchema = v.object({ + uuid: uuidv4Schema, + foreign: v.boolean('expect boolean type'), + createdAt: dateSchema, +}) + +export type CommunityInput = v.InferInput +export type Community = v.InferOutput diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts new file mode 100644 index 000000000..e7459175c --- /dev/null +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -0,0 +1,207 @@ +import { describe, it, expect } from 'bun:test' +import { transactionIdentifierSchema, transactionSchema, TransactionInput, memoSchema } from './transaction.schema' +import { InputTransactionType } from '../enum/InputTransactionType' +import { v4 as uuidv4 } from 'uuid' +import * as v from 'valibot' +import { GradidoUnit, DurationSeconds } from 'gradido-blockchain-js' +import { randomBytes } from 'crypto' + +const transactionLinkCode = (date: Date): string => { + const time = date.getTime().toString(16) + return ( + randomBytes(12) + .toString('hex') + .substring(0, 24 - time.length) + time + ) +} + +describe('transaction schemas', () => { + + describe('transactionIdentifierSchema ', () => { + it('valid, transaction identified by transactionNr and topic', () => { + expect(v.parse(transactionIdentifierSchema, { + transactionNr: 1, + iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + })).toEqual({ + transactionNr: 1, + iotaMessageId: undefined, + iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + }) + }) + it('valid, transaction identified by iotaMessageId and topic', () => { + expect(v.parse(transactionIdentifierSchema, { + iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', + iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + })).toEqual({ + transactionNr: 0, + iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', + iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + }) + }) + it('invalid, missing topic', () => { + expect(() => v.parse(transactionIdentifierSchema, { + transactionNr: 1, + iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', + })).toThrowError(new Error('Invalid key: Expected "iotaTopic" but received undefined')) + }) + it('invalid, transactionNr and iotaMessageId set', () => { + expect(() => v.parse(transactionIdentifierSchema, { + transactionNr: 1, + iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', + iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + })).toThrowError(new Error('expect transactionNr or iotaMessageId not both')) + }) + }) + + describe('transactionSchema', () => { + it('valid, register new user address', () => { + const registerAddress: TransactionInput = { + user: { + communityUuid: uuidv4(), + account: { + userUuid: uuidv4(), + } + }, + type: InputTransactionType.REGISTER_ADDRESS, + createdAt: '2022-01-01T00:00:00.000Z', + } + expect(v.parse(transactionSchema, registerAddress)).toEqual({ + user: { + communityUuid: registerAddress.user.communityUuid, + account: { + userUuid: registerAddress.user.account!.userUuid, + accountNr: 1, + } + }, + type: registerAddress.type, + createdAt: new Date(registerAddress.createdAt), + }) + }) + it('valid, gradido transfer', () => { + const communityUuid = uuidv4() + const gradidoTransfer: TransactionInput = { + user: { + communityUuid, + account: { + userUuid: uuidv4(), + } + }, + linkedUser: { + communityUuid, + account: { + userUuid: uuidv4(), + } + }, + amount: '100', + memo: 'TestMemo', + type: InputTransactionType.GRADIDO_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + } + expect(v.parse(transactionSchema, gradidoTransfer)).toEqual({ + user: { + communityUuid, + account: { + userUuid: gradidoTransfer.user.account!.userUuid, + accountNr: 1, + } + }, + linkedUser: { + communityUuid, + account: { + userUuid: gradidoTransfer.linkedUser!.account!.userUuid, + accountNr: 1, + } + }, + amount: GradidoUnit.fromString(gradidoTransfer.amount!), + memo: gradidoTransfer.memo, + type: gradidoTransfer.type, + createdAt: new Date(gradidoTransfer.createdAt), + }) + }) + + it('valid, gradido creation', () => { + const communityUuid = uuidv4() + const gradidoCreation: TransactionInput = { + user: { + communityUuid, + account: { + userUuid: uuidv4(), + } + }, + linkedUser: { + communityUuid, + account: { + userUuid: uuidv4(), + } + }, + amount: '1000', + memo: 'For your help', + type: InputTransactionType.GRADIDO_CREATION, + createdAt: '2022-01-01T00:00:00.000Z', + targetDate: '2021-11-01T10:00' + } + expect(v.parse(transactionSchema, gradidoCreation)).toEqual({ + user: { + communityUuid, + account: { + userUuid: gradidoCreation.user.account!.userUuid, + accountNr: 1, + } + }, + linkedUser: { + communityUuid, + account: { + userUuid: gradidoCreation.linkedUser!.account!.userUuid, + accountNr: 1, + } + }, + amount: GradidoUnit.fromString(gradidoCreation.amount!), + memo: gradidoCreation.memo, + type: gradidoCreation.type, + createdAt: new Date(gradidoCreation.createdAt), + targetDate: new Date(gradidoCreation.targetDate!), + }) + }) + it('valid, gradido transaction link / deferred transfer', () => { + const gradidoTransactionLink: TransactionInput = { + user: { + communityUuid: uuidv4(), + account: { + userUuid: uuidv4(), + } + }, + linkedUser: { + communityUuid: uuidv4(), + seed: { + seed: transactionLinkCode(new Date()), + } + }, + amount: '100', + memo: 'use link wisely', + type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + timeoutDuration: 60*60*24*30, + } + expect(v.parse(transactionSchema, gradidoTransactionLink)).toEqual({ + user: { + communityUuid: gradidoTransactionLink.user.communityUuid, + account: { + userUuid: gradidoTransactionLink.user.account!.userUuid, + accountNr: 1, + } + }, + linkedUser: { + communityUuid: gradidoTransactionLink.linkedUser!.communityUuid, + seed: { + seed: gradidoTransactionLink.linkedUser!.seed!.seed, + } + }, + amount: GradidoUnit.fromString(gradidoTransactionLink.amount!), + memo: gradidoTransactionLink.memo, + type: gradidoTransactionLink.type, + createdAt: new Date(gradidoTransactionLink.createdAt), + timeoutDuration: new DurationSeconds(gradidoTransactionLink.timeoutDuration!), + }) + }) + }) +}) \ No newline at end of file diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts new file mode 100644 index 000000000..1a2bdae44 --- /dev/null +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -0,0 +1,87 @@ +import * as v from 'valibot' +import { dateFromStringSchema } from './typeConverter.schema' +import { identifierAccountSchema } from './account.schema' +import { InputTransactionType } from '../enum/InputTransactionType' +import { accountTypeToAddressTypeSchema } from './typeConverter.schema' + +// allow TransactionIdentifier to only contain either transactionNr or iotaMessageId +export const transactionIdentifierSchema = v.pipe( + v.object({ + transactionNr: v.nullish( + v.pipe(v.number('expect number type'), v.minValue(0, 'expect number >= 0')), + 0 + ), + iotaMessageId: v.nullish(iotaMessageIdSchema, undefined), + communityId: uuid4ToTopicSchema, + }), + v.custom((value: any) => { + const setFieldsCount = Number(value.transactionNr !== 0) + Number(value.iotaMessageId !== undefined) + if (setFieldsCount !== 1) { + return false + } + return true + }, 'expect transactionNr or iotaMessageId not both') +) +export type TransactionIdentifierInput = v.InferInput +export type TransactionIdentifier = v.InferOutput + +export const transactionSchema = v.object({ + user: identifierAccountSchema, + linkedUser: v.nullish(identifierAccountSchema, undefined), + amount: v.nullish(amountToGradidoUnitSchema, undefined), + memo: v.nullish(memoSchema, undefined), + type: v.enum(InputTransactionType), + createdAt: dateFromStringSchema, + targetDate: v.nullish(dateFromStringSchema, undefined), + timeoutDuration: v.nullish(timeoutDurationSchema, undefined), + accountType: v.nullish(accountTypeToAddressTypeSchema, undefined), +}) + +export type TransactionInput = v.InferInput +export type Transaction = v.InferOutput + +export const creationTransactionSchema = v.object({ + user: identifierAccountSchema, + linkedUser: identifierAccountSchema, + amount: amountToGradidoUnitSchema, + memo: memoSchema, + createdAt: dateFromStringSchema, + targetDate: dateFromStringSchema, +}) + +export type CreationTransactionInput = v.InferInput +export type CreationTransaction = v.InferOutput + +export const transferTransactionSchema = v.object({ + user: identifierAccountSchema, + linkedUser: identifierAccountSchema, + amount: amountToGradidoUnitSchema, + memo: memoSchema, + createdAt: dateFromStringSchema, +}) + +export type TransferTransactionInput = v.InferInput +export type TransferTransaction = v.InferOutput + +// linked user is later needed for move account transaction +export const registerAddressTransactionSchema = v.object({ + user: identifierAccountSchema, + createdAt: dateFromStringSchema, + accountType: accountTypeToAddressTypeSchema, +}) + +export type RegisterAddressTransactionInput = v.InferInput +export type RegisterAddressTransaction = v.InferOutput + + +export const deferredTransferTransactionSchema = v.object({ + user: identifierAccountSchema, + linkedUser: identifierAccountSchema, + amount: amountToGradidoUnitSchema, + memo: memoSchema, + createdAt: dateFromStringSchema, + timeoutDuration: timeoutDurationSchema, +}) + +export type DeferredTransferTransactionInput = v.InferInput +export type DeferredTransferTransaction = v.InferOutput diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts new file mode 100644 index 000000000..b4ca7b7c3 --- /dev/null +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -0,0 +1,51 @@ + +import { accountTypeSchema, addressTypeSchema, confirmedTransactionFromBase64Schema } from './typeConverter.schema' +import * as v from 'valibot' +// only for IDE, bun don't need this to work +import { describe, expect, it } from 'bun:test' +import { dateSchema } from './typeConverter.schema' +import { AddressType_COMMUNITY_AUF } from 'gradido-blockchain-js' +import { AccountType } from '../enum/AccountType' + +describe('basic.schema', () => { + + describe('date', () => { + it('from string', () => { + const date = v.parse(dateSchema, '2021-01-01:10:10') + expect(date.toISOString()).toBe('2021-01-01T10:10:00.000Z') + }) + it('from Date', () => { + const date = v.parse(dateSchema, new Date('2021-01-01')) + expect(date.toISOString()).toBe('2021-01-01T00:00:00.000Z') + }) + it('invalid date', () => { + expect(() => v.parse(dateSchema, 'invalid date')).toThrow(new Error('invalid date')) + }) + }) + + describe('AddressType and AccountType', () => { + it('AddressType from AddressType', () => { + const addressType = v.parse(addressTypeSchema, AddressType_COMMUNITY_AUF) + expect(addressType).toBe(AddressType_COMMUNITY_AUF) + }) + it('AddressType from AccountType', () => { + const accountType = v.parse(addressTypeSchema, AccountType.COMMUNITY_AUF) + expect(accountType).toBe(AddressType_COMMUNITY_AUF) + }) + it('AccountType from AccountType', () => { + const accountType = v.parse(accountTypeSchema, AccountType.COMMUNITY_AUF) + expect(accountType).toBe(AccountType.COMMUNITY_AUF) + }) + it('AccountType from AddressType', () => { + const accountType = v.parse(accountTypeSchema, AddressType_COMMUNITY_AUF) + expect(accountType).toBe(AccountType.COMMUNITY_AUF) + }) + }) + + it('confirmedTransactionFromBase64Schema', () => { + const confirmedTransaction = v.parse(confirmedTransactionFromBase64Schema, 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + expect(confirmedTransaction.getId()).toBe(7) + expect(confirmedTransaction.getConfirmedAt().getSeconds()).toBe(1609464130) + expect(confirmedTransaction.getVersionNumber()).toBe('3.4') + }) +}) diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts new file mode 100644 index 000000000..f3d5fd803 --- /dev/null +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -0,0 +1,125 @@ +import { + AddressType as AddressType, + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, + AddressType_COMMUNITY_HUMAN, + AddressType_COMMUNITY_PROJECT, + AddressType_CRYPTO_ACCOUNT, + AddressType_NONE, + AddressType_SUBACCOUNT, + ConfirmedTransaction, + DeserializeType_CONFIRMED_TRANSACTION, + InteractionDeserialize, + MemoryBlock, +} from 'gradido-blockchain-js' +import { AccountType } from '../enum/AccountType' +// import { AddressType as AddressTypeWrapper } from '../enum/AddressType' +import * as v from 'valibot' + +/** + * dateSchema for creating a date from string or Date object + */ +export const dateSchema = v.pipe( + v.union([ + v.string('expect valid date string'), + v.instance(Date, 'expect Date object') + ]), + v.transform((input) => { + let date: Date + if (input instanceof Date) { + date = input + } else { + date = new Date(input) + } + if (isNaN(date.getTime())) { + throw new Error('invalid date') + } + return date + }) +) + +/** + * AddressType is defined in gradido-blockchain C++ Code + * AccountType is the enum defined in TypeScript but with the same options + * addressTypeSchema and accountTypeSchema are for easy handling and conversion between both + */ + +const accountToAddressMap: Record = { + [AccountType.COMMUNITY_AUF]: AddressType_COMMUNITY_AUF, + [AccountType.COMMUNITY_GMW]: AddressType_COMMUNITY_GMW, + [AccountType.COMMUNITY_HUMAN]: AddressType_COMMUNITY_HUMAN, + [AccountType.COMMUNITY_PROJECT]: AddressType_COMMUNITY_PROJECT, + [AccountType.CRYPTO_ACCOUNT]: AddressType_CRYPTO_ACCOUNT, + [AccountType.SUBACCOUNT]: AddressType_SUBACCOUNT, + [AccountType.NONE]: AddressType_NONE, +} + +const addressToAccountMap: Record = Object.entries(accountToAddressMap).reduce((acc, [accKey, addrVal]) => { + acc[addrVal] = String(accKey) as AccountType + return acc; +}, {} as Record) + +function isAddressType(val: unknown): val is AddressType { + return typeof val === 'number' && Object.keys(addressToAccountMap).includes(val.toString()) +} + +function isAccountType(val: unknown): val is AccountType { + return Object.values(AccountType).includes(val as AccountType); +} + +/** + * Schema for address type, can also convert from account type (if used with v.parse) + */ +export const addressTypeSchema = v.pipe( + v.union([ + v.enum(AccountType, 'expect account type'), + v.custom((val): val is AddressType => isAddressType(val), 'expect AddressType'), + ]), + v.transform((value) => { + if (isAddressType(value)) { + return value; + } + return accountToAddressMap[value as AccountType] ?? AddressType_NONE + }), +) + +/** + * Schema for account type, can also convert from address type (if used with v.parse) + */ +export const accountTypeSchema = v.pipe( + v.union([ + v.custom(isAddressType, 'expect AddressType'), + v.enum(AccountType, 'expect AccountType'), + ]), + v.transform((value) => { + if (isAccountType(value)) { + return value; + } + return addressToAccountMap[value as AddressType] ?? AccountType.NONE; + }), +) + +const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { + const deserializer = new InteractionDeserialize( + MemoryBlock.fromBase64(base64), + DeserializeType_CONFIRMED_TRANSACTION, + ) + deserializer.run() + const confirmedTransaction = deserializer.getConfirmedTransaction() + if (!confirmedTransaction) { + throw new Error("invalid data, couldn't deserialize") + } + return confirmedTransaction +} + +export const confirmedTransactionFromBase64Schema = v.pipe( + v.pipe( + v.string('expect confirmed Transaction base64 as string type'), + v.base64('expect to be valid base64') + ), + v.transform( + (base64: string) => confirmedTransactionFromBase64(base64), + ), +) + + diff --git a/dlt-connector/src/schemas/typeGuard.schema.test.ts b/dlt-connector/src/schemas/typeGuard.schema.test.ts new file mode 100644 index 000000000..02266c0bc --- /dev/null +++ b/dlt-connector/src/schemas/typeGuard.schema.test.ts @@ -0,0 +1,67 @@ +import { describe, it, expect } from 'bun:test' +import { uuidv4Schema, topicIndexSchema, uuid4HashSchema, memoSchema } from './typeGuard.schema' +import * as v from 'valibot' +import { v4 as uuidv4 } from 'uuid' +import { MemoryBlock } from 'gradido-blockchain-js' + +describe('typeGuard.schema', () => { + describe('Uuidv4', () => { + const uuidv4String = uuidv4() + const uuidv4Hash = MemoryBlock.fromHex(uuidv4String.replace(/-/g, '')).calculateHash() + + it('from string to uuidv4', () => { + const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) + expect(uuidv4Value.toString()).toBe(uuidv4String) + }) + + it('from uuidv4 to hash', () => { + const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) + const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4Value) + expect(uuidv4HashParsed.copyAsString()).toBe(uuidv4Hash.copyAsString()) + }) + + it('from uuidv4 string to hash', () => { + const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4String) + expect(uuidv4HashParsed.copyAsString()).toBe(uuidv4Hash.copyAsString()) + }) + + it('from uuidv4 hash to topicIndex (hash in hex format', () => { + const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4String) + const topicIndex = v.parse(topicIndexSchema, uuidv4HashParsed) + expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) + }) + + it('from uuidv4 to topicIndex (hash in hex format)', () => { + const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) + const topicIndex = v.parse(topicIndexSchema, uuidv4Value) + expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) + }) + + it('from uuidv4 string to topicIndex (hash in hex format)', () => { + const topicIndex = v.parse(topicIndexSchema, uuidv4String) + expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) + }) + }) + describe('Basic Type Schemas for transactions', () => { + describe('Memo', () => { + it('min length', () => { + const memoValue = 'memo1' + const memoValueParsed = v.parse(memoSchema, memoValue) + expect(memoValueParsed.toString()).toBe(memoValue) + }) + it('max length', () => { + const memoValue = 's'.repeat(255) + const memoValueParsed = v.parse(memoSchema, memoValue) + expect(memoValueParsed.toString()).toBe(memoValue) + }) + it('to short', () => { + const memoValue = 'memo' + expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length >= 5')) + }) + it('to long', () => { + const memoValue = 's'.repeat(256) + expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length <= 255')) + }) + }) + }) +}) \ No newline at end of file diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts new file mode 100644 index 000000000..6ec33d732 --- /dev/null +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -0,0 +1,146 @@ +/** + * # TypeGuards + * Expand TypeScript Default Types with custom type which a based on a default type (or class) + * Use valibot, so we can describe the type and validate it easy at runtime + * After transpiling TypeScript unique symbol are gone + * Infos at opaque type in typescript: https://evertpot.com/opaque-ts-types/ + * + * declare const validAmount: unique symbol + * export type Amount = number & { [validAmount]: true }; + * Can be compared with using `typedef int Amount;` in C/C++ + * Example: + * To create a instance of Amount: + * `const amount: Amount = v.parse(amountSchema, 1.21)` + * must be called and ensure the value is valid + * If it isn't valid, v.parse will throw an error + */ + +import { validate, version } from 'uuid' +import * as v from 'valibot' +import { MemoryBlock, DurationSeconds, GradidoUnit } from 'gradido-blockchain-js' + +/** + * type guard for uuid v4 + * create with `v.parse(uuidv4Schema, 'uuid')` + * uuidv4 is used for communityUuid and userUuid + */ +declare const validUuidv4: unique symbol +export type Uuidv4 = string & { [validUuidv4]: true }; + +export const uuidv4Schema = v.custom((value) => + (typeof value === 'string' && validate(value) && version(value) === 4), + 'uuid v4 expected' +) + +/** + * type guard for uuid v4 hash + * const uuidv4Value: Uuidv4 = v.parse(uuidv4Schema, 'uuid') + * create with `v.parse(uuidv4HashSchema, uuidv4Value)` + * uuidv4Hash is uuidv4 value hashed with BLAKE2b as Binary Type MemoryBlock from gradido-blockchain similar to Node.js Buffer Type, + * used for iota topic + */ +declare const validUuidv4Hash: unique symbol +export type Uuidv4Hash = MemoryBlock & { [validUuidv4Hash]: true }; + +export const uuid4HashSchema = v.pipe( + uuidv4Schema, + v.transform( + (input: Uuidv4) => MemoryBlock.fromHex(input.replace(/-/g, '')).calculateHash() as Uuidv4Hash, + ) +) + +/** + * type guard for topic index + * const uuidv4Value: Uuidv4 = v.parse(uuidv4Schema, 'uuid') + * const uuidv4Hash: Uuidv4Hash = v.parse(uuid4HashSchema, uuidv4Value) + * create with `v.parse(topicIndexSchema, uuidv4Hash)` + * topicIndex is uuidv4Hash value converted to hex string used for iota topic + * The beauty of valibot allow also parse a uuidv4 string directly to topicIndex + * const topic: TopicIndex = v.parse(topicIndexSchema, 'uuid') + */ +declare const validTopicIndex: unique symbol +export type TopicIndex = string & { [validTopicIndex]: true }; + +export const topicIndexSchema = v.pipe( + v.union([uuidv4Schema, v.custom((val): val is Uuidv4Hash => val instanceof MemoryBlock)]), + v.transform((input) => { + const hash = typeof input === 'string' + ? MemoryBlock.fromHex(input.replace(/-/g, '')).calculateHash() + : input; + return hash.convertToHex() as TopicIndex; + }) +) + +/** + * type guard for memo + * create with `v.parse(memoSchema, 'memo')` + * memo string inside bounds [5, 255] + */ +export const MEMO_MIN_CHARS = 5 +export const MEMO_MAX_CHARS = 255 + +declare const validMemo: unique symbol +export type Memo = string & { [validMemo]: true }; + +export const memoSchema = v.pipe( + v.string('expect string type'), + v.maxLength(MEMO_MAX_CHARS, `expect string length <= ${MEMO_MAX_CHARS}`), + v.minLength(MEMO_MIN_CHARS, `expect string length >= ${MEMO_MIN_CHARS}`), + v.transform( + (input: string) => input as Memo, + ), +) + +/** + * type guard for timeout duration + * create with `v.parse(timeoutDurationSchema, 123)` + * timeout duration is a number in seconds inside bounds + * [1 hour, 3 months] + * for Transaction Links / Deferred Transactions + * seconds starting from createdAt Date in which the transaction link can be redeemed + */ +const LINKED_TRANSACTION_TIMEOUT_DURATION_MIN = 60*60 +const LINKED_TRANSACTION_TIMEOUT_DURATION_MAX = 60*60*24*31*3 + +declare const validTimeoutDuration: unique symbol +export type TimeoutDuration = DurationSeconds & { [validTimeoutDuration]: true }; + +export const timeoutDurationSchema = v.pipe( + v.number('expect number type'), + v.minValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MIN, 'expect number >= 1 hour'), + v.maxValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MAX, 'expect number <= 3 months'), + v.transform( + (input: number) => new DurationSeconds(input) as TimeoutDuration, + ), +) + +/** + * type guard for amount + * create with `v.parse(amountSchema, '123')` + * amount is a string representing a positive decimal number, compatible with decimal.js + */ +declare const validAmount: unique symbol +export type Amount = string & { [validAmount]: true }; + +export const amountSchema = v.pipe( + v.string('expect string type'), + v.regex(/^[0-9]+(\.[0-9]+)?$/, 'expect positive number'), + v.transform( + (input: string) => input as Amount, + ), +) + +/** + * type guard for gradido amount + * create with `v.parse(gradidoAmountSchema, '123')` + * gradido amount is a string representing a positive decimal number, compatible with decimal.js + */ +declare const validGradidoAmount: unique symbol +export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true }; + +export const gradidoAmountSchema = v.pipe( + amountSchema, + v.transform( + (input: Amount) => GradidoUnit.fromString(input) as GradidoAmount, + ), +) \ No newline at end of file diff --git a/dlt-connector/src/server/LogError.test.ts b/dlt-connector/src/server/LogError.test.ts deleted file mode 100644 index 115567a8b..000000000 --- a/dlt-connector/src/server/LogError.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { logger } from '@test/testSetup' - -import { LogError } from './LogError' - -describe('LogError', () => { - it('logs an Error when created', () => { - /* eslint-disable-next-line no-new */ - new LogError('new LogError') - expect(logger.error).toBeCalledWith('new LogError') - }) - - it('logs an Error including additional data when created', () => { - /* eslint-disable-next-line no-new */ - new LogError('new LogError', { some: 'data' }) - expect(logger.error).toBeCalledWith('new LogError', { some: 'data' }) - }) - - it('does not contain additional data in Error object when thrown', () => { - try { - throw new LogError('new LogError', { someWeirdValue123: 'arbitraryData456' }) - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - } catch (e: any) { - expect(e.stack).not.toMatch(/(someWeirdValue123|arbitraryData456)/i) - } - }) -}) diff --git a/dlt-connector/src/server/LogError.ts b/dlt-connector/src/server/LogError.ts deleted file mode 100644 index 69aca1978..000000000 --- a/dlt-connector/src/server/LogError.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { logger } from '@/logging/logger' - -export class LogError extends Error { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(msg: string, ...details: any[]) { - super(msg) - logger.error(msg, ...details) - } -} diff --git a/dlt-connector/src/server/cors.ts b/dlt-connector/src/server/cors.ts deleted file mode 100644 index 95663695d..000000000 --- a/dlt-connector/src/server/cors.ts +++ /dev/null @@ -1,8 +0,0 @@ -import corsLib from 'cors' - -const corsOptions = { - origin: '*', - exposedHeaders: ['token'], -} - -export const cors = corsLib(corsOptions) diff --git a/dlt-connector/src/server/createServer.ts b/dlt-connector/src/server/createServer.ts deleted file mode 100755 index 9cc29124c..000000000 --- a/dlt-connector/src/server/createServer.ts +++ /dev/null @@ -1,79 +0,0 @@ -import 'reflect-metadata' - -import { ApolloServer } from '@apollo/server' -import { expressMiddleware } from '@apollo/server/express4' -import bodyParser from 'body-parser' -import cors from 'cors' -import express, { Express } from 'express' -// graphql -import { slowDown } from 'express-slow-down' -import helmet from 'helmet' -import { Logger } from 'log4js' - -import { schema } from '@/graphql/schema' -import { logger as dltLogger } from '@/logging/logger' - -type ServerDef = { apollo: ApolloServer; app: Express } - -interface MyContext { - token?: string -} - -const createServer = async ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - // context: any = serverContext, - logger: Logger = dltLogger, - // localization: i18n.I18n = i18n, -): Promise => { - logger.addContext('user', 'unknown') - logger.debug('createServer...') - - // Express Server - const app = express() - - // Apollo Server - const apollo = new ApolloServer({ - schema: await schema(), - introspection: true, - // context, - // plugins - logger, - }) - // Helmet helps secure Express apps by setting HTTP response headers. - app.use(helmet()) - - // rate limiter/ slow down to many requests - const limiter = slowDown({ - windowMs: 1000, // 1 second - delayAfter: 10, // Allow 10 requests per 1 second. - delayMs: (hits) => hits * 50, // Add 100 ms of delay to every request after the 10th one. - /** - * So: - * - * - requests 1-10 are not delayed. - * - request 11 is delayed by 550ms - * - request 12 is delayed by 600ms - * - request 13 is delayed by 650ms - * - * and so on. After 1 seconds, the delay is reset to 0. - */ - }) - app.use(limiter) - // because of nginx proxy, needed for limiter - app.set('trust proxy', 1) - - await apollo.start() - app.use( - '/', - cors(), - bodyParser.json(), - expressMiddleware(apollo, { - context: async ({ req }) => ({ token: req.headers.token }), - }), - ) - logger.debug('createServer...successful') - - return { apollo, app } -} - -export default createServer diff --git a/dlt-connector/src/utils/derivationHelper.test.ts b/dlt-connector/src/utils/derivationHelper.test.ts index 6d3d690ee..63e7b6993 100644 --- a/dlt-connector/src/utils/derivationHelper.test.ts +++ b/dlt-connector/src/utils/derivationHelper.test.ts @@ -1,6 +1,6 @@ -import 'reflect-metadata' - import { hardenDerivationIndex, HARDENED_KEY_BITMASK } from './derivationHelper' +// only for IDE, bun don't need this to work +import { describe, expect, it } from 'bun:test' describe('utils', () => { it('test bitmask for hardened keys', () => { diff --git a/dlt-connector/src/utils/network.ts b/dlt-connector/src/utils/network.ts new file mode 100644 index 000000000..8c4244c36 --- /dev/null +++ b/dlt-connector/src/utils/network.ts @@ -0,0 +1,51 @@ +import net from 'node:net' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { CONFIG } from '../config' + +export async function isPortOpen( + url: string, + timeoutMs: number = CONFIG.CONNECT_TIMEOUT_MS, +): Promise { + return new Promise((resolve) => { + const socket = new net.Socket() + const { hostname, port } = new URL(url) + + // auto-destroy socket after timeout + const timer = setTimeout(() => { + socket.destroy() + resolve(false) + }, timeoutMs) + + socket.connect(Number(port), hostname, () => { + // connection successful + clearTimeout(timer) + socket.end() + resolve(true) + }) + + socket.on('error', (err: any) => { + clearTimeout(timer) + socket.destroy() + const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.network.isPortOpen`) + logger.addContext('url', url) + logger.error(`${err.message}: ${err.code}`) + resolve(false) + }) + }) +} + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) + +export async function isPortOpenRetry( + url: string, + timeoutMs: number = CONFIG.CONNECT_TIMEOUT_MS, + delayMs: number = CONFIG.CONNECT_RETRY_DELAY_MS, + retries: number = CONFIG.CONNECT_RETRY_COUNT, +): Promise { + for (let i = 0; i < retries; i++) { + if (await isPortOpen(url, timeoutMs)) return true + await wait(delayMs) + } + throw new Error(`${url} port is not open after ${retries} retries`) +} \ No newline at end of file diff --git a/dlt-connector/src/utils/typeConverter.test.ts b/dlt-connector/src/utils/typeConverter.test.ts deleted file mode 100644 index 527e9dd17..000000000 --- a/dlt-connector/src/utils/typeConverter.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import 'reflect-metadata' - -import { base64ToBuffer, uuid4ToHash, uuid4ToBuffer } from './typeConverter' - -describe('utils/typeConverter', () => { - it('uuid4ToBuffer', () => { - expect(uuid4ToBuffer('4f28e081-5c39-4dde-b6a4-3bde71de8d65')).toStrictEqual( - Buffer.from('4f28e0815c394ddeb6a43bde71de8d65', 'hex'), - ) - }) - - it('iotaTopicFromCommunityUUID', () => { - expect(uuid4ToHash('4f28e081-5c39-4dde-b6a4-3bde71de8d65')).toBe( - '3138b3590311fdf0a823e173caa9487b7d275c23fab07106b4b1364cb038affd', - ) - }) - - it('base64ToBuffer', () => { - expect(base64ToBuffer('MTizWQMR/fCoI+FzyqlIe30nXCP6sHEGtLE2TLA4r/0=')).toStrictEqual( - Buffer.from('3138b3590311fdf0a823e173caa9487b7d275c23fab07106b4b1364cb038affd', 'hex'), - ) - }) -}) diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts deleted file mode 100644 index 219b95376..000000000 --- a/dlt-connector/src/utils/typeConverter.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable camelcase */ -import { - AddressType, - AddressType_COMMUNITY_AUF, - AddressType_COMMUNITY_GMW, - AddressType_COMMUNITY_HUMAN, - AddressType_COMMUNITY_PROJECT, - AddressType_CRYPTO_ACCOUNT, - AddressType_NONE, - AddressType_SUBACCOUNT, - ConfirmedTransaction, - DeserializeType_CONFIRMED_TRANSACTION, - InteractionDeserialize, - MemoryBlock, -} from 'gradido-blockchain-js' - -import { AccountType } from '@/graphql/enum/AccountType' -import { LogError } from '@/server/LogError' - -export const uuid4ToBuffer = (uuid: string): Buffer => { - // Remove dashes from the UUIDv4 string - const cleanedUUID = uuid.replace(/-/g, '') - - // Create a Buffer object from the hexadecimal values - const buffer = Buffer.from(cleanedUUID, 'hex') - - return buffer -} - -export const uuid4ToMemoryBlock = (uuid: string): MemoryBlock => { - // Remove dashes from the UUIDv4 string - return MemoryBlock.fromHex(uuid.replace(/-/g, '')) -} - -export const uuid4sToMemoryBlock = (uuid: string[]): MemoryBlock => { - let resultHexString = '' - for (let i = 0; i < uuid.length; i++) { - resultHexString += uuid[i].replace(/-/g, '') - } - return MemoryBlock.fromHex(resultHexString) -} - -export const uuid4ToHash = (communityUUID: string): MemoryBlock => { - return uuid4ToMemoryBlock(communityUUID).calculateHash() -} - -export const base64ToBuffer = (base64: string): Buffer => { - return Buffer.from(base64, 'base64') -} - -export const communityUuidToTopic = (communityUUID: string): string => { - return uuid4ToHash(communityUUID).convertToHex() -} - -export function getEnumValue>( - enumType: T, - value: number | string, -): T[keyof T] | undefined { - if (typeof value === 'number' && typeof enumType === 'object') { - return enumType[value as keyof T] as T[keyof T] - } else if (typeof value === 'string') { - for (const key in enumType) { - if (enumType[key as keyof T] === value) { - return enumType[key as keyof T] as T[keyof T] - } - } - } - return undefined -} - -export const accountTypeToAddressType = (type: AccountType): AddressType => { - switch (type) { - case AccountType.COMMUNITY_AUF: - return AddressType_COMMUNITY_AUF - case AccountType.COMMUNITY_GMW: - return AddressType_COMMUNITY_GMW - case AccountType.COMMUNITY_HUMAN: - return AddressType_COMMUNITY_HUMAN - case AccountType.COMMUNITY_PROJECT: - return AddressType_COMMUNITY_PROJECT - case AccountType.CRYPTO_ACCOUNT: - return AddressType_CRYPTO_ACCOUNT - case AccountType.SUBACCOUNT: - return AddressType_SUBACCOUNT - default: - return AddressType_NONE - } -} - -export const addressTypeToAccountType = (type: AddressType): AccountType => { - switch (type) { - case AddressType_COMMUNITY_AUF: - return AccountType.COMMUNITY_AUF - case AddressType_COMMUNITY_GMW: - return AccountType.COMMUNITY_GMW - case AddressType_COMMUNITY_HUMAN: - return AccountType.COMMUNITY_HUMAN - case AddressType_COMMUNITY_PROJECT: - return AccountType.COMMUNITY_PROJECT - case AddressType_CRYPTO_ACCOUNT: - return AccountType.CRYPTO_ACCOUNT - case AddressType_SUBACCOUNT: - return AccountType.SUBACCOUNT - default: - return AccountType.NONE - } -} - -export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { - const deserializer = new InteractionDeserialize( - MemoryBlock.fromBase64(base64), - DeserializeType_CONFIRMED_TRANSACTION, - ) - deserializer.run() - const confirmedTransaction = deserializer.getConfirmedTransaction() - if (!confirmedTransaction) { - throw new LogError("invalid data, couldn't deserialize") - } - return confirmedTransaction -} diff --git a/dlt-connector/test/ApolloServerMock.ts b/dlt-connector/test/ApolloServerMock.ts deleted file mode 100644 index c13df2407..000000000 --- a/dlt-connector/test/ApolloServerMock.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ApolloServer } from '@apollo/server' -import { addMocksToSchema } from '@graphql-tools/mock' - -import { schema } from '@/graphql/schema' - -let apolloTestServer: ApolloServer - -export async function createApolloTestServer() { - if (apolloTestServer === undefined) { - apolloTestServer = new ApolloServer({ - // addMocksToSchema accepts a schema instance and provides - // mocked data for each field in the schema - schema: addMocksToSchema({ - schema: await schema(), - preserveResolvers: true, - }), - }) - } - return apolloTestServer -} diff --git a/dlt-connector/test/testSetup.ts b/dlt-connector/test/testSetup.ts deleted file mode 100644 index 71170cbf0..000000000 --- a/dlt-connector/test/testSetup.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { logger } from '@/logging/logger' - -jest.setTimeout(1000000) - -jest.mock('@/logging/logger', () => { - const originalModule = jest.requireActual('@/logging/logger') - return { - __esModule: true, - ...originalModule, - logger: { - addContext: jest.fn(), - trace: jest.fn(), - debug: jest.fn(), - warn: jest.fn(), - info: jest.fn(), - error: jest.fn(), - fatal: jest.fn(), - }, - } -}) - -export { logger } diff --git a/dlt-connector/tsconfig.json b/dlt-connector/tsconfig.json index 2ce9731e3..51dc1dd77 100644 --- a/dlt-connector/tsconfig.json +++ b/dlt-connector/tsconfig.json @@ -1,88 +1,104 @@ { + "include": ["src/**/*", "types/**/*"], "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./build", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Language and Environment */ + "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ - "paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - "@/*": ["src/*"], - "@arg/*": ["src/graphql/arg/*"], - "@enum/*": ["src/graphql/enum/*"], - "@input/*": ["src/graphql/input/*"], - "@model/*": ["src/graphql/model/*"], - "@resolver/*": ["src/graphql/resolver/*"], - "@test/*": ["test/*"], - "@proto/*" : ["src/proto/*"], - "@validator/*" : ["src/graphql/validator/*"], - }, - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - "typeRoots": ["node_modules/@types", "@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'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Modules */ + "module": "ES2022", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Experimental Options */ - "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - }, - "references": [ - { - // add 'prepend' if you want to include the referenced project in your output file - // "prepend": true - } - ] + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } } diff --git a/dlt-connector/types/global.d.ts b/dlt-connector/types/global.d.ts new file mode 100644 index 000000000..793328940 --- /dev/null +++ b/dlt-connector/types/global.d.ts @@ -0,0 +1,2 @@ +// types/global.d.ts +/// = 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - 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" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -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== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-by-default@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== - -ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -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== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" - integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -iniparser@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/iniparser/-/iniparser-1.0.5.tgz#836d6befe6dfbfcee0bccf1cf9f2acc7027f783d" - integrity sha512-i40MWqgTU6h/70NtMsDVVDLjDYWwcIR1yIEVDPfxZIJno9z9L4s83p/V7vAu2i48Vj0gpByrkGFub7ko9XvPrw== - -inquirer@^7.3.3: - 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" - -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-bun-module@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.2.1.tgz#495e706f42e29f086fd5fe1ac3c51f106062b9fc" - integrity sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q== - dependencies: - semver "^7.6.3" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" - integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== - dependencies: - hasown "^2.0.2" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - 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-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -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== - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" - integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== - -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" - integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== - dependencies: - "@jest/types" "^27.5.1" - execa "^5.0.0" - throat "^6.0.1" - -jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - -jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== - dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - prompts "^2.0.1" - yargs "^16.2.0" - -jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== - dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^27.5.1" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== - dependencies: - detect-newline "^3.0.0" - -jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - -jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" - -jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - -jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== - -jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== - dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - -jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" - -jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== - dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - -jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== - dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" - -jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - -jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.8.1" - graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" - throat "^6.0.1" - -jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - -jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== - dependencies: - "@babel/core" "^7.7.2" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^27.5.1" - graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" - -jest-util@^27.0.0, jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== - dependencies: - "@jest/types" "^27.5.1" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^27.5.1" - leven "^3.1.0" - pretty-format "^27.5.1" - -jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== - dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^27.5.1" - string-length "^4.0.1" - -jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^27.2.4: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== - dependencies: - "@jest/core" "^27.5.1" - import-local "^3.0.2" - jest-cli "^27.5.1" - -jose@^5.2.2: - version "5.9.2" - resolved "https://registry.yarnpkg.com/jose/-/jose-5.9.2.tgz#22a22da06edb8fb9e583aa24bafc1e8457b4db92" - integrity sha512-ILI2xx/I57b20sd7rHZvgiiQrmp2mcotwsAH+5ajbpFQbrYVQdNHYlQhoA5cFb78CgtBOxtC05TeA+mcgkuCqQ== - -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== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -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 "^2.0.1" - -jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json5@2.x, json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonrpc-ts-client@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/jsonrpc-ts-client/-/jsonrpc-ts-client-0.2.3.tgz#ec50c413d84041564e6c8a4003ab4bb360d5cfcc" - integrity sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g== - dependencies: - axios "^0.24.0" - debug "^4.3.3" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -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" - -libphonenumber-js@^1.10.53: - version "1.11.9" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.9.tgz#e653042b11da2b50b7ea3b206fa7ca998436ae99" - integrity sha512-Zs5wf5HaWzW2/inlupe2tstl0I/Tbqo7lH20ZLr6Is58u7Dz2n+gRFGNlj9/gWxFvNfp9+YyDsiegjNhdixB9A== - -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" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.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: - p-locate "^5.0.0" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -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.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== - -lodash@^4.17.19, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log4js@^6.7.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" - integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== - dependencies: - date-format "^4.0.14" - debug "^4.3.4" - flatted "^3.2.7" - rfdc "^1.3.0" - streamroller "^3.1.5" - -loglevel@^1.6.8: - version "1.9.2" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" - integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^7.10.1, lru-cache@^7.14.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -make-promises-safe@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/make-promises-safe/-/make-promises-safe-5.1.0.tgz#dd9d311f555bcaa144f12e225b3d37785f0aa8f2" - integrity sha512-AfdZ49rtyhQR/6cqVKGoH7y4ql7XkS5HJI1lZm0/5N6CQosy1eYbBJ/qbhkKHzo17UH7M918Bysf6XB9f3kS1g== - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memory-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-stream/-/memory-stream-1.0.0.tgz#481dfd259ccdf57b03ec2c9632960044180e73c2" - integrity sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww== - dependencies: - readable-stream "^3.4.0" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -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 sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -micromatch@^4.0.4: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "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@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" - integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== - -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, 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, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@2.1.3, ms@^2.1.1, ms@^2.1.3: - version "2.1.3" - 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== - -nan@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" - integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== - -napi-build-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" - integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== - -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" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -negotiator@0.6.3, negotiator@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -neon-cli@^0.8: - version "0.8.3" - resolved "https://registry.yarnpkg.com/neon-cli/-/neon-cli-0.8.3.tgz#dea3a00021a07b9ef05e73464e45c94a2bf0fd3a" - integrity sha512-I44MB8PD0AEyFr/b5icR4sX1tsjdkb2T2uWEStG4Uf5C/jzalZPn7eazbQrW6KDyXNd8bc+LVuOr1v6CGTa1KQ== - dependencies: - chalk "^4.1.0" - command-line-args "^5.1.1" - command-line-commands "^3.0.1" - command-line-usage "^6.1.0" - git-config "0.0.7" - handlebars "^4.7.6" - inquirer "^7.3.3" - make-promises-safe "^5.1.0" - rimraf "^3.0.2" - semver "^7.3.2" - toml "^3.0.0" - ts-typed-json "^0.3.2" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - -node-abi@^2.21.0: - version "2.30.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" - integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== - dependencies: - semver "^5.4.1" - -node-abi@^3.3.0: - version "3.68.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.68.0.tgz#8f37fb02ecf4f43ebe694090dcb52e0c4cc4ba25" - integrity sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A== - dependencies: - semver "^7.3.5" - -node-abort-controller@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" - integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== - -node-addon-api@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" - integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== - -node-api-headers@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.3.0.tgz#bb32c6b3e33fb0004bd93c66787bf00998c834ea" - integrity sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg== - -node-fetch@^2.6.12, node-fetch@^2.6.7: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@^4.8.1: - version "4.8.2" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" - integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw== - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== - -nodemon@^2.0.20: - version "2.0.22" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258" - integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ== - dependencies: - chokidar "^3.5.2" - debug "^3.2.7" - ignore-by-default "^1.0.1" - minimatch "^3.1.2" - pstree.remy "^1.1.8" - semver "^5.7.1" - simple-update-notifier "^1.0.7" - supports-color "^5.5.0" - touch "^3.1.0" - undefsafe "^2.0.5" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-path@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" - integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== - dependencies: - which "^1.2.10" - -npm-run-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" - integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== - dependencies: - path-key "^3.0.0" - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npm-which@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" - integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== - dependencies: - commander "^2.9.0" - npm-path "^2.0.2" - which "^1.2.10" - -npmlog@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -npmlog@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== - dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== - -nwsapi@^2.2.0: - version "2.2.12" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" - integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== - -object-assign@^4, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.fromentries@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - -object.groupby@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" - integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - -object.values@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0, onetime@^5.1.2: - 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.9.3: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.5" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -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@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.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" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -parseurl@~1.3.3: - version "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 sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, 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-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" - integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== - -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 sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -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== - -picocolors@^1.0.0, picocolors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pirates@^4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -prebuild-install@^6.1.2: - version "6.1.4" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.4.tgz#ae3c0142ad611d58570b89af4986088a4937e00f" - integrity sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ== - dependencies: - detect-libc "^1.0.3" - expand-template "^2.0.3" - github-from-package "0.0.0" - minimist "^1.2.3" - mkdirp-classic "^0.5.3" - napi-build-utils "^1.0.1" - node-abi "^2.21.0" - npmlog "^4.0.1" - pump "^3.0.0" - rc "^1.2.7" - simple-get "^3.0.3" - tar-fs "^2.0.0" - tunnel-agent "^0.6.0" - -"prebuildify@git+https://github.com/einhornimmond/prebuildify#cmake_js": - version "6.0.1" - resolved "git+https://github.com/einhornimmond/prebuildify#91f4e765611fcc1e8123df0c8fc84aec5ab55b31" - dependencies: - cmake-js "^7.2.1" - execspawn "^1.0.1" - minimist "^1.2.5" - mkdirp-classic "^0.5.3" - node-abi "^3.3.0" - npm-run-path "^3.1.0" - npm-which "^3.0.1" - pump "^3.0.0" - tar-fs "^2.1.0" - -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== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.8.7: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -pretty-format@^27.0.0, pretty-format@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== - dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -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== - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -proxy-addr@~2.0.5, proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.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== - -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -pstree.remy@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" - integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== - -pump@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" - integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.0, punycode@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -qs@6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -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" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -readable-stream@^2.0.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -reduce-flatten@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" - integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== - -reflect-metadata@^0.1.13: - version "0.1.14" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859" - integrity sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A== - -regexp-tree@~0.1.1: - version "0.1.27" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" - integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== - -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -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== - -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== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - -resolve.exports@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" - integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== - -resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^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" - -retry@0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - -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== - -rfdc@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" - integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== - -rimraf@^3.0.0, 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== - -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: - queue-microtask "^1.2.2" - -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== - dependencies: - tslib "^1.9.0" - -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - -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" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -safe-regex@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" - integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== - dependencies: - regexp-tree "~0.1.1" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -semver@7.x, semver@^7.0.0, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -semver@^5.4.1, semver@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@~7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -send@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -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 "^3.0.0" - -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== - -side-channel@^1.0.4, side-channel@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - -simple-get@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" - integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== - dependencies: - decompress-response "^4.2.0" - once "^1.3.1" - simple-concat "^1.0.0" - -simple-update-notifier@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" - integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== - dependencies: - semver "~7.0.0" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" - integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.20" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89" - integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"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" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -streamroller@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" - integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== - dependencies: - date-format "^4.0.14" - debug "^4.3.4" - fs-extra "^8.1.0" - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, 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== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -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== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -supports-color@^5.3.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== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - 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" - -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -table-layout@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" - integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== - dependencies: - array-back "^4.0.1" - deep-extend "~0.6.0" - typical "^5.2.0" - wordwrapjs "^4.0.0" - -tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -tar-fs@^2.0.0, tar-fs@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" - integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^5.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -throat@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" - integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -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" - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -toml@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" - integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== - -touch@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" - integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== - -tough-cookie@^4.0.0: - version "4.1.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" - integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-jest@^27.0.5: - version "27.1.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.5.tgz#0ddf1b163fbaae3d5b7504a1e65c914a95cff297" - integrity sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "20.x" - -ts-node@^10.9.1: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -ts-typed-json@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ts-typed-json/-/ts-typed-json-0.3.2.tgz#f4f20f45950bae0a383857f7b0a94187eca1b56a" - integrity sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA== - -tsconfig-paths@^3.15.0: - version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tsconfig-paths@^4.1.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" - integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== - dependencies: - json5 "^2.2.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.8.1, tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.2, tslib@^2.6.2, tslib@^2.6.3: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== - -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" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -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.2.1" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -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-graphql@^2.0.0-beta.2: - version "2.0.0-rc.2" - resolved "https://registry.yarnpkg.com/type-graphql/-/type-graphql-2.0.0-rc.2.tgz#1086ef889737bd21a9f0ed0fb1041dce2d918e92" - integrity sha512-DJ8erG1cmjteMrOhFIkBHOqRM+L+wCJxvNjbbj1Y+q2r4HZkB1qOSS4ZD4AaoAfRPAp1yU23gMtmzf0jen/FFA== - dependencies: - "@graphql-yoga/subscription" "^5.0.0" - "@types/node" "^20.14.0" - "@types/semver" "^7.5.6" - graphql-query-complexity "^0.12.0" - semver "^7.5.4" - tslib "^2.6.2" - -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" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript@^4.9.4: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - -typical@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== - -typical@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" - integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== - -uglify-js@^3.1.4: - version "3.19.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" - integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -undefsafe@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" - integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== - dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-join@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" - integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -util-extend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - integrity sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA== - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@^9.0.0, uuid@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - -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" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -validate-npm-package-license@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw== - dependencies: - builtins "^1.0.3" - -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.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" - integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== - -vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-mimetype@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" - integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which@^1.2.10: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - 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" - -wide-align@^1.1.0, wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -word-wrap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - -wordwrapjs@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" - integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== - dependencies: - reduce-flatten "^2.0.0" - typical "^5.2.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@^7.4.6: - version "7.5.10" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -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@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -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@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -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@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - 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" - 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 6e2269a4992a1e3cf5837d1fbd7158404ab44903 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 1 Aug 2025 12:54:26 +0200 Subject: [PATCH 025/226] introduce valibot, elysia.js, trpc and drop apollo/graphql-server --- bun.lock | 5 + dlt-connector/bun.lock | 6 +- dlt-connector/package.json | 2 +- dlt-connector/src/client/GradidoNode/api.ts | 167 +++++++++++++++++ .../src/client/GradidoNode/input.schema.ts | 49 ++--- .../src/client/GradidoNode/jsonrpc.api.ts | 174 ------------------ .../src/client/GradidoNode/jsonrpc.ts | 54 ++++++ .../src/client/{ => backend}/BackendClient.ts | 6 +- .../backend/community.schema.test.ts} | 6 +- .../backend/community.schema.ts} | 4 +- dlt-connector/src/data/Uuidv4Hash.ts | 33 ++++ dlt-connector/src/enum/AccountType.ts | 3 +- dlt-connector/src/enum/AddressType.ts | 2 + dlt-connector/src/index.ts | 37 ++-- .../AbstractRemoteKeyPair.role.ts | 2 +- .../ForeignCommunityKeyPair.role.ts | 2 +- .../RemoteAccountKeyPair.role.ts | 2 +- .../CommunityRootTransaction.role.ts | 2 +- dlt-connector/src/schemas/account.schema.ts | 3 +- dlt-connector/src/schemas/base.schema.ts | 11 ++ .../src/schemas/transaction.schema.ts | 22 +-- .../src/schemas/typeConverter.schema.test.ts | 12 +- .../src/schemas/typeConverter.schema.ts | 89 ++------- .../src/schemas/typeGuard.schema.test.ts | 70 ++----- dlt-connector/src/schemas/typeGuard.schema.ts | 113 ++++++++---- dlt-connector/src/server/index.ts | 77 ++++++++ dlt-connector/src/utils/typeConverter.ts | 72 ++++++++ 27 files changed, 607 insertions(+), 418 deletions(-) create mode 100644 dlt-connector/src/client/GradidoNode/api.ts delete mode 100644 dlt-connector/src/client/GradidoNode/jsonrpc.api.ts create mode 100644 dlt-connector/src/client/GradidoNode/jsonrpc.ts rename dlt-connector/src/client/{ => backend}/BackendClient.ts (93%) rename dlt-connector/src/{schemas/rpcParameter.schema.test.ts => client/backend/community.schema.test.ts} (76%) rename dlt-connector/src/{schemas/rpcParameter.schema.ts => client/backend/community.schema.ts} (79%) create mode 100644 dlt-connector/src/data/Uuidv4Hash.ts create mode 100644 dlt-connector/src/schemas/base.schema.ts create mode 100644 dlt-connector/src/server/index.ts create mode 100644 dlt-connector/src/utils/typeConverter.ts diff --git a/bun.lock b/bun.lock index 7087ef10f..c6242a0e6 100644 --- a/bun.lock +++ b/bun.lock @@ -184,12 +184,15 @@ "dependencies": { "database": "*", "esbuild": "^0.25.2", + "jose": "^4.14.4", "log4js": "^6.9.1", + "shared": "*", "zod": "^3.25.61", }, "devDependencies": { "@biomejs/biome": "2.0.0", "@types/node": "^17.0.21", + "type-graphql": "^1.1.1", "typescript": "^4.9.5", }, }, @@ -295,6 +298,7 @@ "await-semaphore": "0.1.3", "class-validator": "^0.13.2", "config-schema": "*", + "core": "*", "cors": "2.8.5", "database": "*", "decimal.js-light": "^2.5.1", @@ -423,6 +427,7 @@ "dependencies": { "decimal.js-light": "^2.5.1", "esbuild": "^0.25.2", + "jose": "^4.14.4", "log4js": "^6.9.1", "zod": "^3.25.61", }, diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 80b8a8c7b..2d3860900 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -5,7 +5,7 @@ "name": "dlt-connector", "dependencies": { "@iota/client": "^2.2.4", - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#217d03b", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#9a5f392", }, "devDependencies": { "@biomejs/biome": "2.0.0", @@ -232,7 +232,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#217d03b", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#cmake_js" } }, "gradido-gradido-blockchain-js-217d03b"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#9a5f392", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-9a5f392"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], @@ -356,7 +356,7 @@ "prebuild-install": ["prebuild-install@6.1.4", "", { "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^3.0.3", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ=="], - "prebuildify": ["prebuildify@github:einhornimmond/prebuildify#91f4e76", { "dependencies": { "cmake-js": "^7.2.1", "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", "npm-run-path": "^3.1.0", "npm-which": "^3.0.1", "pump": "^3.0.0", "tar-fs": "^2.1.0" }, "bin": { "prebuildify": "./bin.js" } }, "einhornimmond-prebuildify-91f4e76"], + "prebuildify": ["prebuildify@github:einhornimmond/prebuildify#65d9445", { "dependencies": { "cmake-js": "^7.2.1", "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", "npm-run-path": "^3.1.0", "npm-which": "^3.0.1", "pump": "^3.0.0", "tar-fs": "^2.1.0" }, "bin": { "prebuildify": "./bin.js" } }, "einhornimmond-prebuildify-65d9445"], "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index bb935e8c7..08804bc0f 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -12,7 +12,7 @@ "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#217d03b", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#9a5f392", "@iota/client": "^2.2.4" }, "devDependencies": { diff --git a/dlt-connector/src/client/GradidoNode/api.ts b/dlt-connector/src/client/GradidoNode/api.ts new file mode 100644 index 000000000..fa8672a23 --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/api.ts @@ -0,0 +1,167 @@ +import { AddressType, ConfirmedTransaction } from 'gradido-blockchain-js' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import * as v from 'valibot' +import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' +import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' +import { rpcCall, rpcCallResolved, GradidoNodeRequestError } from './jsonrpc' +import { + TransactionsRangeInput, + TransactionIdentifierInput, + transactionsRangeSchema, + transactionIdentifierSchema +} from './input.schema' +import { Uuidv4Hash } from '../../data/Uuidv4Hash' +import { Hex32, Hex32Input, hex32Schema } from '../../schemas/typeGuard.schema' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) + +/** + * getTransactions + * get list of confirmed transactions from a specific community + * @param input fromTransactionId is the id of the first transaction to return + * @param input maxResultCount is the max number of transactions to return + * @param input topic is the community topic + * @returns list of confirmed transactions + * @throws GradidoNodeRequestError + * @example + * ``` + * const transactions = await getTransactions({ + * fromTransactionId: 1, + * maxResultCount: 100, + * topic: communityUuid, + * }) + * ``` + */ +async function getTransactions(input: TransactionsRangeInput): Promise { + const parameter = { ...v.parse(transactionsRangeSchema, input), format: 'base64' } + const result = await rpcCallResolved<{transactions: string[]}>('getTransactions', parameter) + return result.transactions.map((transactionBase64) => + v.parse(confirmedTransactionSchema, transactionBase64), + ) +} + +/** + * getTransaction + * get a specific confirmed transaction from a specific community + * @param transactionIdentifier + * @returns the confirmed transaction or undefined if transaction is not found + * @throws GradidoNodeRequestError + */ +async function getTransaction(transactionIdentifier: TransactionIdentifierInput) +: Promise { + const parameter = { + ...v.parse(transactionIdentifierSchema, transactionIdentifier), + format: 'base64', + } + const response = await rpcCall<{ transaction: string }>('gettransaction', parameter) + if (response.isSuccess()) { + return v.parse(confirmedTransactionSchema, response.result.transaction) + } + if (response.isError()) { + if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { + return undefined + } + } + throw new GradidoNodeRequestError(response.error.message, response) +} + +/** + * getLastTransaction + * get the last confirmed transaction from a specific community + * @param iotaTopic the community topic + * @returns the last confirmed transaction or undefined if blockchain for community is empty or not found + * @throws GradidoNodeRequestError + */ + +async function getLastTransaction(iotaTopic: Uuidv4Hash): Promise { + const response = await rpcCall<{ transaction: string }>('getlasttransaction', { + format: 'base64', + topic: iotaTopic.getAsHexString(), + }) + if (response.isSuccess()) { + return v.parse(confirmedTransactionSchema, response.result.transaction) + } + if (response.isError()) { + if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { + return undefined + } + throw new GradidoNodeRequestError(response.error.message, response) + } +} + +/** + * getAddressType + * get the address type of a specific user + * can be used to check if user/account exists on blockchain + * look also for gmw, auf and deferred transfer accounts + * @param pubkey the public key of the user or account + * @param iotaTopic the community topic + * @returns the address type of the user/account or undefined + * @throws GradidoNodeRequestError + */ + +async function getAddressType(pubkey: Hex32Input, iotaTopic: Uuidv4Hash): Promise { + const parameter = { + pubkey: v.parse(hex32Schema, pubkey), + communityId: iotaTopic.getAsHexString(), + } + const response = await rpcCallResolved<{ addressType: string }>('getaddresstype', parameter) + return v.parse(addressTypeSchema, response.addressType) +} + +/** + * findUserByNameHash + * find a user by name hash + * @param nameHash the name hash of the user + * @param iotaTopic the community topic + * @returns the public key of the user as hex32 string or undefined if user is not found + * @throws GradidoNodeRequestError + */ +async function findUserByNameHash(nameHash: Uuidv4Hash, iotaTopic: Uuidv4Hash): Promise { + const parameter = { + nameHash: nameHash.getAsHexString(), + communityId: iotaTopic.getAsHexString(), + } + const response = await rpcCall<{ pubkey: string; timeUsed: string }>('findUserByNameHash', parameter) + if(response.isSuccess()) { + logger.info(`call findUserByNameHash, used ${response.result.timeUsed}`) + return v.parse(hex32Schema, response.result.pubkey) + } + if (response.isError() && response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND) { + logger.debug(`call findUserByNameHash, return with error: ${response.error.message}`) + } + return undefined +} + +/** + * getTransactionsForAccount + * get list of confirmed transactions for a specific account + * @param transactionRange the range of transactions to return + * @param pubkey the public key of the account + * @returns list of confirmed transactions + * @throws GradidoNodeRequestError + */ +async function getTransactionsForAccount( + transactionRange: TransactionsRangeInput, + pubkey: Hex32Input, +): Promise { + const parameter = { + ...v.parse(transactionsRangeSchema, transactionRange), + pubkey: v.parse(hex32Schema, pubkey), + format: 'base64', + } + const response = await rpcCallResolved<{transactions: string[]}>('listtransactionsforaddress', parameter) + return response.transactions.map((transactionBase64) => + v.parse(confirmedTransactionSchema, transactionBase64), + ) +} + +export { + getTransaction, + getLastTransaction, + getTransactions, + getAddressType, + getTransactionsForAccount, + findUserByNameHash, +} diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts index 27b4ad79e..b207f935a 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -1,33 +1,36 @@ import * as v from 'valibot' -import { uuid4ToTopicSchema } from '../../schemas/typeConverter.schema' +import { hex32Schema, iotaMessageIdSchema } from '../../schemas/typeGuard.schema' -export enum TransactionFormatType { - BASE64 = 'base64', - JSON = 'json', -} - -export const transactionFormatTypeSchema = v.nullish( - v.enum(TransactionFormatType), - TransactionFormatType.BASE64 -) - -export type TransactionFormatTypeInput = v.InferInput - -export const getTransactionsInputSchema = v.object({ - format: transactionFormatTypeSchema, +export const transactionsRangeSchema = v.object({ // default value is 1, from first transactions fromTransactionId: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1), // default value is 100, max 100 transactions maxResultCount: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100), - communityId: uuid4ToTopicSchema, + topic: hex32Schema, }) -export type GetTransactionsInputType = v.InferInput +export type TransactionsRangeInput = v.InferInput -export const getTransactionInputSchema = v.object({ - transactionIdentifier: v.object({ - iotaTopic: uuid4ToTopicSchema, - transactionNr: v.number(), - iotaMessageId: v.string(), + +// allow TransactionIdentifier to only contain either transactionNr or iotaMessageId +export const transactionIdentifierSchema = v.pipe( + v.object({ + transactionNr: v.nullish( + v.pipe(v.number('expect number type'), v.minValue(1, 'expect number >= 1')), + undefined + ), + iotaMessageId: v.nullish(iotaMessageIdSchema, undefined), + topic: hex32Schema, }), -}) \ No newline at end of file + v.custom((value: any) => { + const setFieldsCount = Number(value.transactionNr !== undefined) + Number(value.iotaMessageId !== undefined) + if (setFieldsCount !== 1) { + return false + } + return true + }, 'expect transactionNr or iotaMessageId not both') +) + +export type TransactionIdentifierInput = v.InferInput +export type TransactionIdentifier = v.InferOutput + diff --git a/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts b/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts deleted file mode 100644 index 83a700b4d..000000000 --- a/dlt-connector/src/client/GradidoNode/jsonrpc.api.ts +++ /dev/null @@ -1,174 +0,0 @@ -/* eslint-disable camelcase */ -import { AddressType, ConfirmedTransaction, MemoryBlock, stringToAddressType } from 'gradido-blockchain-js' -import JsonRpcClient from 'jsonrpc-ts-client' -import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' - -import { CONFIG } from '../../config' -import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import * as v from 'valibot' -import { confirmedTransactionFromBase64Schema } from '../../schemas/typeConverter.schema' -import { isPortOpenRetry } from '../../utils/network' -import { TransactionIdentifierInput, transactionIdentifierSchema } from '../../schemas/transaction.schema' -import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' -import { GetTransactionsInputType, TransactionFormatTypeInput, getTransactionsInputSchema, transactionFormatTypeSchema } from './input.schema' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) - -const client = new JsonRpcClient({ - url: CONFIG.NODE_SERVER_URL, -}) - - -interface ConfirmedTransactionList { - transactions: string[] - timeUsed: string -} - -interface ConfirmedTransactionResponse { - transaction: string - timeUsed: string -} - -interface AddressTypeResult { - addressType: string -} - -interface FindUserResponse { - pubkey: string - timeUsed: string -} - -export class GradidoNodeRequestError extends Error { - private response?: JsonRpcEitherResponse - constructor(message: string, response?: JsonRpcEitherResponse) { - super(message) - this.name = 'GradidoNodeRequestError' - this.response = response - } - getResponse(): JsonRpcEitherResponse | undefined { - return this.response - } -} - -function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { - if (response.isSuccess()) { - return onSuccess(response.result) - } else if (response.isError()) { - throw new GradidoNodeRequestError(response.error.message, response) - } - throw new GradidoNodeRequestError('no success and no error') -} - -async function getTransactions(input: GetTransactionsInputType): Promise { - const parameter = v.parse(getTransactionsInputSchema, input) - logger.debug('call getTransactions with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('getTransactions', parameter) - return resolveResponse(response, (result: ConfirmedTransactionList) => { - logger.info(`call getTransactions, used ${result.timeUsed}`) - return result.transactions.map((transactionBase64) => - v.parse(confirmedTransactionFromBase64Schema, transactionBase64), - ) - }) -} - -async function getTransaction( - transactionIdentifier: TransactionIdentifierInput, - format: TransactionFormatTypeInput -) -: Promise { - const parameter = { - ...v.parse(transactionIdentifierSchema, transactionIdentifier), - format: v.parse(transactionFormatTypeSchema, format), - } - logger.debug('call gettransaction with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('gettransaction', parameter) - return resolveResponse(response, (result: ConfirmedTransactionResponse) => { - logger.info(`call gettransaction, used ${result.timeUsed}`) - return result.transaction && result.transaction !== '' - ? v.parse(confirmedTransactionFromBase64Schema, result.transaction) - : undefined - }) -} - -async function getLastTransaction(iotaTopic: string): Promise { - const parameter = { - format: 'base64', - communityId: iotaTopic, - } - logger.debug('call getlasttransaction with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('getlasttransaction', parameter) - return resolveResponse(response, (result: ConfirmedTransactionResponse) => { - logger.info(`call getlasttransaction, used ${result.timeUsed}`) - return result.transaction && result.transaction !== '' - ? v.parse(confirmedTransactionFromBase64Schema, result.transaction) - : undefined - }) -} - -async function getAddressType(pubkey: Buffer, iotaTopic: string): Promise { - const parameter = { - pubkey: pubkey.toString('hex'), - communityId: iotaTopic, - } - logger.debug('call getaddresstype with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('getaddresstype', parameter) - return resolveResponse(response, (result: AddressTypeResult) => { - logger.info(`call getaddresstype`) - return stringToAddressType(result.addressType) - }) -} - -async function findUserByNameHash(nameHash: MemoryBlock, iotaTopic: string): Promise { - const parameter = { - nameHash: nameHash.convertToHex(), - communityId: iotaTopic, - } - logger.debug('call findUserByNameHash with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('findUserByNameHash', parameter) - if (response.isError() && response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND) { - return undefined - } - return resolveResponse(response, (result: FindUserResponse) => { - logger.info(`call findUserByNameHash, used ${result.timeUsed}`) - return result.pubkey && result.pubkey !== '' ? MemoryBlock.fromHex(result.pubkey) : undefined - }) -} - -async function getTransactionsForAccount( - pubkey: MemoryBlock, - iotaTopic: string, - maxResultCount = 0, - firstTransactionNr = 1, -): Promise { - const parameter = { - pubkey: pubkey.convertToHex(), - format: 'base64', - firstTransactionNr, - maxResultCount, - communityId: iotaTopic, - } - logger.debug('call listtransactionsforaddress with ', parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - const response = await client.exec('listtransactionsforaddress', parameter) - return resolveResponse(response, (result: ConfirmedTransactionList) => { - logger.info(`call listtransactionsforaddress, used ${result.timeUsed}`) - return result.transactions.map((transactionBase64) => - v.parse(confirmedTransactionFromBase64Schema, transactionBase64), - ) - }) -} - -export { - getTransaction, - getLastTransaction, - getTransactions, - getAddressType, - getTransactionsForAccount, - findUserByNameHash, -} diff --git a/dlt-connector/src/client/GradidoNode/jsonrpc.ts b/dlt-connector/src/client/GradidoNode/jsonrpc.ts new file mode 100644 index 000000000..6cd053d87 --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/jsonrpc.ts @@ -0,0 +1,54 @@ +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' +import { isPortOpenRetry } from '../../utils/network' +import { CONFIG } from '../../config' +import JsonRpcClient from 'jsonrpc-ts-client' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) + +export const client = new JsonRpcClient({ + url: CONFIG.NODE_SERVER_URL, +}) + +export class GradidoNodeRequestError extends Error { + private response?: JsonRpcEitherResponse + constructor(message: string, response?: JsonRpcEitherResponse) { + super(message) + this.name = 'GradidoNodeRequestError' + this.response = response + } + getResponse(): JsonRpcEitherResponse | undefined { + return this.response + } +} + +// return result on success or throw error +export function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { + if (response.isSuccess()) { + return onSuccess(response.result) + } else if (response.isError()) { + throw new GradidoNodeRequestError(response.error.message, response) + } + throw new GradidoNodeRequestError('no success and no error') +} + +type WithTimeUsed = T & { timeUsed?: string } + +// template rpcCall, check first if port is open before executing json rpc 2.0 request +export async function rpcCall(method: string, parameter: any): Promise> { + logger.debug('call %s with %s', method, parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + return client.exec(method, parameter) +} + +// template rpcCall, check first if port is open before executing json rpc 2.0 request, throw error on failure, return result on success +export async function rpcCallResolved(method: string, parameter: any): Promise { + const response = await rpcCall>(method, parameter) + return resolveResponse(response, (result: WithTimeUsed) => { + if (result.timeUsed) { + logger.info(`call %s, used ${result.timeUsed}`, method) + } + return result as T + }) +} \ No newline at end of file diff --git a/dlt-connector/src/client/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts similarity index 93% rename from dlt-connector/src/client/BackendClient.ts rename to dlt-connector/src/client/backend/BackendClient.ts index 4ee556f17..50904d198 100644 --- a/dlt-connector/src/client/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -1,10 +1,10 @@ import { gql, GraphQLClient } from 'graphql-request' import { SignJWT } from 'jose' -import { CONFIG } from '../config' -import { communitySchema, type Community } from '../schemas/rpcParameter.schema' +import { CONFIG } from '../../config' +import { communitySchema, type Community } from './community.schema' import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' import * as v from 'valibot' const homeCommunity = gql` diff --git a/dlt-connector/src/schemas/rpcParameter.schema.test.ts b/dlt-connector/src/client/backend/community.schema.test.ts similarity index 76% rename from dlt-connector/src/schemas/rpcParameter.schema.test.ts rename to dlt-connector/src/client/backend/community.schema.test.ts index 8680c3958..42cf9dc7e 100644 --- a/dlt-connector/src/schemas/rpcParameter.schema.test.ts +++ b/dlt-connector/src/client/backend/community.schema.test.ts @@ -1,10 +1,10 @@ -import { communitySchema } from './rpcParameter.schema' -import { uuidv4Schema } from './typeGuard.schema' +import { communitySchema } from './community.schema' +import { uuidv4Schema } from '../../schemas/typeGuard.schema' import * as v from 'valibot' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' -describe('rpcParameter.schema', () => { +describe('community.schema', () => { it('community', () => { expect(v.parse(communitySchema, { uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', diff --git a/dlt-connector/src/schemas/rpcParameter.schema.ts b/dlt-connector/src/client/backend/community.schema.ts similarity index 79% rename from dlt-connector/src/schemas/rpcParameter.schema.ts rename to dlt-connector/src/client/backend/community.schema.ts index 0a05dd86c..af8cf01bd 100644 --- a/dlt-connector/src/schemas/rpcParameter.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -1,6 +1,6 @@ import * as v from 'valibot' -import { uuidv4Schema } from './typeGuard.schema' -import { dateSchema } from './typeConverter.schema' +import { uuidv4Schema } from '../../schemas/typeGuard.schema' +import { dateSchema } from '../../schemas/typeConverter.schema' /** * Schema Definitions for rpc call parameter, when dlt-connector is called from backend diff --git a/dlt-connector/src/data/Uuidv4Hash.ts b/dlt-connector/src/data/Uuidv4Hash.ts new file mode 100644 index 000000000..541f412d2 --- /dev/null +++ b/dlt-connector/src/data/Uuidv4Hash.ts @@ -0,0 +1,33 @@ +import { MemoryBlock } from 'gradido-blockchain-js' +import { Uuidv4, Hex32, hex32Schema, MemoryBlock32, memoryBlock32Schema } from '../schemas/typeGuard.schema' +import * as v from 'valibot' + +/** + * Uuidv4Hash is a class that represents a uuidv4 BLAKE2b hash + * to get the hash, the - in the uuidv4 will be removed and the result interpreted as hex string + * then the hash will be calculated with BLAKE2b algorithm + * crypto_generichash from libsodium will be called when calling MemoryBlock.calculateHash() + * + * This will be used as NameHash for user identification (user uuid as input) + * This will be used as IotaTopic for transactions (community uuid as input) + */ +export class Uuidv4Hash { + uuidv4Hash: MemoryBlock32 + // used for caching hex string representation of uuidv4Hash + uuidv4HashString: Hex32 | undefined + + constructor(uuidv4: Uuidv4) { + this.uuidv4Hash = v.parse(memoryBlock32Schema, MemoryBlock.fromHex(uuidv4.replace(/-/g, '')).calculateHash()) + } + + getAsMemoryBlock(): MemoryBlock32 { + return this.uuidv4Hash + } + + getAsHexString(): Hex32 { + if (!this.uuidv4HashString) { + this.uuidv4HashString = v.parse(hex32Schema, this.uuidv4Hash) + } + return this.uuidv4HashString + } +} diff --git a/dlt-connector/src/enum/AccountType.ts b/dlt-connector/src/enum/AccountType.ts index 8d8e5fcc0..b1c2b1150 100644 --- a/dlt-connector/src/enum/AccountType.ts +++ b/dlt-connector/src/enum/AccountType.ts @@ -10,5 +10,6 @@ export enum AccountType { COMMUNITY_AUF = 'COMMUNITY_AUF', // community compensation and environment founds account COMMUNITY_PROJECT = 'COMMUNITY_PROJECT', // no creations allowed SUBACCOUNT = 'SUBACCOUNT', // no creations allowed - CRYPTO_ACCOUNT = 'CRYPTO_ACCOUNT', // user control his keys, no creations + CRYPTO_ACCOUNT = 'CRYPTO_ACCOUNT', // user control his keys, no creations, + DEFERRED_TRANSFER = 'DEFERRED_TRANSFER', // no creations allowed } diff --git a/dlt-connector/src/enum/AddressType.ts b/dlt-connector/src/enum/AddressType.ts index 0e0d8bb30..8ac2f05fc 100644 --- a/dlt-connector/src/enum/AddressType.ts +++ b/dlt-connector/src/enum/AddressType.ts @@ -6,6 +6,7 @@ import { AddressType_CRYPTO_ACCOUNT, AddressType_NONE, AddressType_SUBACCOUNT, + AddressType_DEFERRED_TRANSFER, } from 'gradido-blockchain-js' export enum AddressType { @@ -16,4 +17,5 @@ export enum AddressType { CRYPTO_ACCOUNT = AddressType_CRYPTO_ACCOUNT, NONE = AddressType_NONE, SUBACCOUNT = AddressType_SUBACCOUNT, + DEFERRED_TRANSFER = AddressType_DEFERRED_TRANSFER, } \ No newline at end of file diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index ce5ab8fb3..7681719ed 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -4,11 +4,13 @@ import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { getLogger, configure } from 'log4js' import { readFileSync } from 'node:fs' import { isPortOpenRetry } from './utils/network' -import { BackendClient } from './client/BackendClient' +import { BackendClient } from './client/backend/BackendClient' import { KeyPairCacheManager } from './KeyPairCacheManager' -import { communityUuidToTopicSchema } from './schemas/rpcParameter.schema' -import { parse } from 'valibot' -import { getTransaction } from './client/GradidoNode/jsonrpc.api' +import { getTransaction } from './client/GradidoNode/api' +import { Uuidv4Hash } from './data/Uuidv4Hash' +import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' +import { keyGenerationSeedSchema } from './schemas/base.schema' +import * as v from 'valibot' async function main() { // configure log4js @@ -16,21 +18,12 @@ async function main() { const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) configure(options) const logger = getLogger('dlt') - // TODO: replace with schema validation - if (CONFIG.IOTA_HOME_COMMUNITY_SEED) { - try { - const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) - if (seed.size() < 32) { - throw new Error('seed need to be greater than 32 Bytes') - } - } catch (error) { - logger.error( - 'IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long', - ) - process.exit(1) - } + // check if valid seed for root key pair generation is present + if (!v.safeParse(keyGenerationSeedSchema, CONFIG.IOTA_HOME_COMMUNITY_SEED).success) { + logger.error('IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long') + process.exit(1) } - + // load crypto keys for gradido blockchain lib loadCryptoKeys( MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), @@ -46,19 +39,19 @@ async function main() { await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) const homeCommunity = await backend.getHomeCommunityDraft() KeyPairCacheManager.getInstance().setHomeCommunityUUID(homeCommunity.uuid) - logger.info('home community topic: %s', parse(communityUuidToTopicSchema, homeCommunity.uuid)) + const topic = new Uuidv4Hash(homeCommunity.uuid).getAsHexString() + logger.info('home community topic: %s', topic) logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) // ask gradido node if community blockchain was created try { - const topic = parse(communityUuidToTopicSchema, homeCommunity.uuid) - if (!await getTransaction(1, topic)) { + if (!await getTransaction({ transactionNr: 1, topic })) { // if not exist, create community root transaction await SendToIotaContext(homeCommunity) } } catch (e) { logger.error('error requesting gradido node: ', e) } - + // listen for rpc request from backend (replace graphql with json rpc) const app = new Elysia() .get('/', () => "Hello Elysia") .listen(CONFIG.DLT_CONNECTOR_PORT, () => { diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts index 0a4168f0d..235deadac 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts @@ -1,5 +1,5 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { communityUuidToTopicSchema } from '../../schemas/rpcParameter.schema' +import { communityUuidToTopicSchema } from '../../client/backend/community.schema' import * as v from 'valibot' export abstract class AbstractRemoteKeyPairRole { diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts index f4b25cd57..803b1d216 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -1,6 +1,6 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { getTransaction } from '../../client/GradidoNode/jsonrpc.api' +import { getTransaction } from '../../client/GradidoNode/api' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' import { GradidoNodeInvalidTransactionError, GradidoNodeMissingTransactionError } from '../../errors' diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts index 6432366f4..4ae1af7d9 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -1,6 +1,6 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { findUserByNameHash } from '../../client/GradidoNode/jsonrpc.api' +import { findUserByNameHash } from '../../client/GradidoNode/api' import { IdentifierAccount } from '../../schemas/account.schema' import { GradidoNodeMissingUserError, ParameterError } from '../../errors' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts index 8771c6789..3beaa633d 100644 --- a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts @@ -10,7 +10,7 @@ import { import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' -import { Community, CommunityInput, communitySchema } from '../../schemas/rpcParameter.schema' +import { Community, CommunityInput, communitySchema } from '../../client/backend/community.schema' import * as v from 'valibot' export class CommunityRootTransactionRole extends AbstractTransactionRole { diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts index 4242558b3..ee85b5cea 100644 --- a/dlt-connector/src/schemas/account.schema.ts +++ b/dlt-connector/src/schemas/account.schema.ts @@ -1,6 +1,5 @@ - import * as v from 'valibot' -import { uuidv4Schema } from './typeConverter.schema' +import { uuidv4Schema } from './typeGuard.schema' // use code from transaction links export const identifierSeedSchema = v.object({ diff --git a/dlt-connector/src/schemas/base.schema.ts b/dlt-connector/src/schemas/base.schema.ts new file mode 100644 index 000000000..8a9f3af3d --- /dev/null +++ b/dlt-connector/src/schemas/base.schema.ts @@ -0,0 +1,11 @@ +import * as v from 'valibot' +import { MemoryBlock } from 'gradido-blockchain-js' + +export const keyGenerationSeedSchema = v.pipe( + v.string('expect string type'), + v.hexadecimal('expect hexadecimal string'), + v.length(64, 'expect seed length minimum 64 characters (32 Bytes)'), + v.transform( + (input: string) => MemoryBlock.fromHex(input), + ), +) \ No newline at end of file diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index 1a2bdae44..ac654da5e 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -4,29 +4,9 @@ import { identifierAccountSchema } from './account.schema' import { InputTransactionType } from '../enum/InputTransactionType' import { accountTypeToAddressTypeSchema } from './typeConverter.schema' -// allow TransactionIdentifier to only contain either transactionNr or iotaMessageId -export const transactionIdentifierSchema = v.pipe( - v.object({ - transactionNr: v.nullish( - v.pipe(v.number('expect number type'), v.minValue(0, 'expect number >= 0')), - 0 - ), - iotaMessageId: v.nullish(iotaMessageIdSchema, undefined), - communityId: uuid4ToTopicSchema, - }), - v.custom((value: any) => { - const setFieldsCount = Number(value.transactionNr !== 0) + Number(value.iotaMessageId !== undefined) - if (setFieldsCount !== 1) { - return false - } - return true - }, 'expect transactionNr or iotaMessageId not both') -) -export type TransactionIdentifierInput = v.InferInput -export type TransactionIdentifier = v.InferOutput export const transactionSchema = v.object({ - user: identifierAccountSchema, + user: identifierAccountScmhema, linkedUser: v.nullish(identifierAccountSchema, undefined), amount: v.nullish(amountToGradidoUnitSchema, undefined), memo: v.nullish(memoSchema, undefined), diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index b4ca7b7c3..7537e3b59 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -1,10 +1,10 @@ -import { accountTypeSchema, addressTypeSchema, confirmedTransactionFromBase64Schema } from './typeConverter.schema' +import { accountTypeSchema, addressTypeSchema, confirmedTransactionSchema } from './typeConverter.schema' import * as v from 'valibot' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' import { dateSchema } from './typeConverter.schema' -import { AddressType_COMMUNITY_AUF } from 'gradido-blockchain-js' +import { AddressType_COMMUNITY_AUF, AddressType_COMMUNITY_PROJECT } from 'gradido-blockchain-js' import { AccountType } from '../enum/AccountType' describe('basic.schema', () => { @@ -24,6 +24,10 @@ describe('basic.schema', () => { }) describe('AddressType and AccountType', () => { + it('AddressType from string', () => { + const addressType = v.parse(addressTypeSchema, 'COMMUNITY_AUF') + expect(addressType).toBe(AddressType_COMMUNITY_AUF) + }) it('AddressType from AddressType', () => { const addressType = v.parse(addressTypeSchema, AddressType_COMMUNITY_AUF) expect(addressType).toBe(AddressType_COMMUNITY_AUF) @@ -42,8 +46,8 @@ describe('basic.schema', () => { }) }) - it('confirmedTransactionFromBase64Schema', () => { - const confirmedTransaction = v.parse(confirmedTransactionFromBase64Schema, 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + it('confirmedTransactionSchema', () => { + const confirmedTransaction = v.parse(confirmedTransactionSchema, 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') expect(confirmedTransaction.getId()).toBe(7) expect(confirmedTransaction.getConfirmedAt().getSeconds()).toBe(1609464130) expect(confirmedTransaction.getVersionNumber()).toBe('3.4') diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index f3d5fd803..4f6eb6b42 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -1,20 +1,10 @@ import { AddressType as AddressType, - AddressType_COMMUNITY_AUF, - AddressType_COMMUNITY_GMW, - AddressType_COMMUNITY_HUMAN, - AddressType_COMMUNITY_PROJECT, - AddressType_CRYPTO_ACCOUNT, - AddressType_NONE, - AddressType_SUBACCOUNT, ConfirmedTransaction, - DeserializeType_CONFIRMED_TRANSACTION, - InteractionDeserialize, - MemoryBlock, } from 'gradido-blockchain-js' import { AccountType } from '../enum/AccountType' -// import { AddressType as AddressTypeWrapper } from '../enum/AddressType' import * as v from 'valibot' +import { confirmedTransactionFromBase64, isAddressType, toAddressType, toAccountType } from '../utils/typeConverter' /** * dateSchema for creating a date from string or Date object @@ -42,45 +32,14 @@ export const dateSchema = v.pipe( * AddressType is defined in gradido-blockchain C++ Code * AccountType is the enum defined in TypeScript but with the same options * addressTypeSchema and accountTypeSchema are for easy handling and conversion between both - */ - -const accountToAddressMap: Record = { - [AccountType.COMMUNITY_AUF]: AddressType_COMMUNITY_AUF, - [AccountType.COMMUNITY_GMW]: AddressType_COMMUNITY_GMW, - [AccountType.COMMUNITY_HUMAN]: AddressType_COMMUNITY_HUMAN, - [AccountType.COMMUNITY_PROJECT]: AddressType_COMMUNITY_PROJECT, - [AccountType.CRYPTO_ACCOUNT]: AddressType_CRYPTO_ACCOUNT, - [AccountType.SUBACCOUNT]: AddressType_SUBACCOUNT, - [AccountType.NONE]: AddressType_NONE, -} - -const addressToAccountMap: Record = Object.entries(accountToAddressMap).reduce((acc, [accKey, addrVal]) => { - acc[addrVal] = String(accKey) as AccountType - return acc; -}, {} as Record) - -function isAddressType(val: unknown): val is AddressType { - return typeof val === 'number' && Object.keys(addressToAccountMap).includes(val.toString()) -} - -function isAccountType(val: unknown): val is AccountType { - return Object.values(AccountType).includes(val as AccountType); -} - -/** * Schema for address type, can also convert from account type (if used with v.parse) */ export const addressTypeSchema = v.pipe( v.union([ v.enum(AccountType, 'expect account type'), - v.custom((val): val is AddressType => isAddressType(val), 'expect AddressType'), + v.custom(isAddressType, 'expect AddressType'), ]), - v.transform((value) => { - if (isAddressType(value)) { - return value; - } - return accountToAddressMap[value as AccountType] ?? AddressType_NONE - }), + v.transform((value) => toAddressType(value)), ) /** @@ -91,34 +50,24 @@ export const accountTypeSchema = v.pipe( v.custom(isAddressType, 'expect AddressType'), v.enum(AccountType, 'expect AccountType'), ]), - v.transform((value) => { - if (isAccountType(value)) { - return value; - } - return addressToAccountMap[value as AddressType] ?? AccountType.NONE; - }), + v.transform((value) => toAccountType(value)), ) -const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { - const deserializer = new InteractionDeserialize( - MemoryBlock.fromBase64(base64), - DeserializeType_CONFIRMED_TRANSACTION, - ) - deserializer.run() - const confirmedTransaction = deserializer.getConfirmedTransaction() - if (!confirmedTransaction) { - throw new Error("invalid data, couldn't deserialize") - } - return confirmedTransaction -} - -export const confirmedTransactionFromBase64Schema = v.pipe( - v.pipe( - v.string('expect confirmed Transaction base64 as string type'), - v.base64('expect to be valid base64') - ), - v.transform( - (base64: string) => confirmedTransactionFromBase64(base64), +export const confirmedTransactionSchema = v.pipe( + v.union([ + v.instance(ConfirmedTransaction, 'expect ConfirmedTransaction'), + v.pipe( + v.string('expect confirmed Transaction base64 as string type'), + v.base64('expect to be valid base64') + ), + ]), + v.transform( + (data: string | ConfirmedTransaction) => { + if (data instanceof ConfirmedTransaction) { + return data + } + return confirmedTransactionFromBase64(data) + }, ), ) diff --git a/dlt-connector/src/schemas/typeGuard.schema.test.ts b/dlt-connector/src/schemas/typeGuard.schema.test.ts index 02266c0bc..27781c868 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.test.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.test.ts @@ -1,67 +1,37 @@ import { describe, it, expect } from 'bun:test' -import { uuidv4Schema, topicIndexSchema, uuid4HashSchema, memoSchema } from './typeGuard.schema' +import { uuidv4Schema, memoSchema } from './typeGuard.schema' import * as v from 'valibot' import { v4 as uuidv4 } from 'uuid' -import { MemoryBlock } from 'gradido-blockchain-js' describe('typeGuard.schema', () => { describe('Uuidv4', () => { const uuidv4String = uuidv4() - const uuidv4Hash = MemoryBlock.fromHex(uuidv4String.replace(/-/g, '')).calculateHash() it('from string to uuidv4', () => { const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) expect(uuidv4Value.toString()).toBe(uuidv4String) }) - - it('from uuidv4 to hash', () => { - const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) - const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4Value) - expect(uuidv4HashParsed.copyAsString()).toBe(uuidv4Hash.copyAsString()) - }) - - it('from uuidv4 string to hash', () => { - const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4String) - expect(uuidv4HashParsed.copyAsString()).toBe(uuidv4Hash.copyAsString()) - }) - - it('from uuidv4 hash to topicIndex (hash in hex format', () => { - const uuidv4HashParsed = v.parse(uuid4HashSchema, uuidv4String) - const topicIndex = v.parse(topicIndexSchema, uuidv4HashParsed) - expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) - }) - - it('from uuidv4 to topicIndex (hash in hex format)', () => { - const uuidv4Value = v.parse(uuidv4Schema, uuidv4String) - const topicIndex = v.parse(topicIndexSchema, uuidv4Value) - expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) - }) - - it('from uuidv4 string to topicIndex (hash in hex format)', () => { - const topicIndex = v.parse(topicIndexSchema, uuidv4String) - expect(topicIndex.toString()).toBe(uuidv4Hash.convertToHex()) - }) }) describe('Basic Type Schemas for transactions', () => { - describe('Memo', () => { - it('min length', () => { - const memoValue = 'memo1' - const memoValueParsed = v.parse(memoSchema, memoValue) - expect(memoValueParsed.toString()).toBe(memoValue) - }) - it('max length', () => { - const memoValue = 's'.repeat(255) - const memoValueParsed = v.parse(memoSchema, memoValue) - expect(memoValueParsed.toString()).toBe(memoValue) - }) - it('to short', () => { - const memoValue = 'memo' - expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length >= 5')) - }) - it('to long', () => { - const memoValue = 's'.repeat(256) - expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length <= 255')) - }) + describe('Memo', () => { + it('min length', () => { + const memoValue = 'memo1' + const memoValueParsed = v.parse(memoSchema, memoValue) + expect(memoValueParsed.toString()).toBe(memoValue) + }) + it('max length', () => { + const memoValue = 's'.repeat(255) + const memoValueParsed = v.parse(memoSchema, memoValue) + expect(memoValueParsed.toString()).toBe(memoValue) + }) + it('to short', () => { + const memoValue = 'memo' + expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length >= 5')) + }) + it('to long', () => { + const memoValue = 's'.repeat(256) + expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length <= 255')) }) }) + }) }) \ No newline at end of file diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts index 6ec33d732..d5a1a32dd 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -13,6 +13,7 @@ * `const amount: Amount = v.parse(amountSchema, 1.21)` * must be called and ensure the value is valid * If it isn't valid, v.parse will throw an error + * Alternatively v.safeParse can be used, this don't throw but it return null on error */ import { validate, version } from 'uuid' @@ -27,48 +28,89 @@ import { MemoryBlock, DurationSeconds, GradidoUnit } from 'gradido-blockchain-js declare const validUuidv4: unique symbol export type Uuidv4 = string & { [validUuidv4]: true }; -export const uuidv4Schema = v.custom((value) => - (typeof value === 'string' && validate(value) && version(value) === 4), - 'uuid v4 expected' +export const uuidv4Schema = v.pipe( + v.string('expect string type'), + v.custom((value) => + (typeof value === 'string' && validate(value) && version(value) === 4), + 'uuid v4 expected' + ), + v.transform( + (input: string) => input as Uuidv4, + ), +) + +export type Uuidv4Input = v.InferInput + +/** + * type guard for memory block size 32 + * create with `v.parse(memoryBlock32Schema, MemoryBlock.fromHex('39568d7e148a0afee7f27a67dbf7d4e87d1fdec958e2680df98a469690ffc1a2'))` + * memoryBlock32 is a non-empty MemoryBlock with size 32 + */ + +declare const validMemoryBlock32: unique symbol +export type MemoryBlock32 = MemoryBlock & { [validMemoryBlock32]: true }; + +export const memoryBlock32Schema = v.pipe( + v.instance(MemoryBlock, 'expect MemoryBlock type'), + v.custom( + (val): boolean => val instanceof MemoryBlock && val.size() === 32 && !val.isEmpty(), + 'expect MemoryBlock size = 32 and not empty' + ), + v.transform( + (input: MemoryBlock) => input as MemoryBlock32, + ), ) /** - * type guard for uuid v4 hash - * const uuidv4Value: Uuidv4 = v.parse(uuidv4Schema, 'uuid') - * create with `v.parse(uuidv4HashSchema, uuidv4Value)` - * uuidv4Hash is uuidv4 value hashed with BLAKE2b as Binary Type MemoryBlock from gradido-blockchain similar to Node.js Buffer Type, - * used for iota topic + * type guard for hex string of length 64 (binary size = 32) + * create with `v.parse(hex32Schema, '39568d7e148a0afee7f27a67dbf7d4e87d1fdec958e2680df98a469690ffc1a2')` + * or `v.parse(hex32Schema, MemoryBlock.fromHex('39568d7e148a0afee7f27a67dbf7d4e87d1fdec958e2680df98a469690ffc1a2'))` + * hex32 is a hex string of length 64 (binary size = 32) */ -declare const validUuidv4Hash: unique symbol -export type Uuidv4Hash = MemoryBlock & { [validUuidv4Hash]: true }; +declare const validHex32: unique symbol +export type Hex32 = string & { [validHex32]: true }; -export const uuid4HashSchema = v.pipe( - uuidv4Schema, - v.transform( - (input: Uuidv4) => MemoryBlock.fromHex(input.replace(/-/g, '')).calculateHash() as Uuidv4Hash, - ) +export const hex32Schema = v.pipe( + v.union([ + v.pipe( + v.string('expect string type'), + v.hexadecimal('expect hexadecimal string'), + v.length(64, 'expect string length = 64'), + ), + memoryBlock32Schema, + ]), + v.transform( + (input: string | MemoryBlock32 | Hex32) => { + if (typeof input === 'string') { + return input as Hex32 + } + return input.convertToHex() as Hex32 + }, + ), ) -/** - * type guard for topic index - * const uuidv4Value: Uuidv4 = v.parse(uuidv4Schema, 'uuid') - * const uuidv4Hash: Uuidv4Hash = v.parse(uuid4HashSchema, uuidv4Value) - * create with `v.parse(topicIndexSchema, uuidv4Hash)` - * topicIndex is uuidv4Hash value converted to hex string used for iota topic - * The beauty of valibot allow also parse a uuidv4 string directly to topicIndex - * const topic: TopicIndex = v.parse(topicIndexSchema, 'uuid') - */ -declare const validTopicIndex: unique symbol -export type TopicIndex = string & { [validTopicIndex]: true }; +export type Hex32Input = v.InferInput -export const topicIndexSchema = v.pipe( - v.union([uuidv4Schema, v.custom((val): val is Uuidv4Hash => val instanceof MemoryBlock)]), - v.transform((input) => { - const hash = typeof input === 'string' - ? MemoryBlock.fromHex(input.replace(/-/g, '')).calculateHash() - : input; - return hash.convertToHex() as TopicIndex; - }) +/** + * type guard for iota message id + * create with `v.parse(iotaMessageIdSchema, '822387692a7cfd3f07f25742e91e248af281d771ee03a432c2e178e5533f786c')` + * iota message id is a hex string of length 64 + */ +declare const validIotaMessageId: unique symbol +export type IotaMessageId = Hex32 & { [validIotaMessageId]: true }; + +export const iotaMessageIdSchema = v.pipe( + v.union([ + v.pipe( + v.string('expect string type'), + v.hexadecimal('expect hexadecimal string'), + v.length(64, 'expect string length = 64'), + ), + memoryBlock32Schema, + ]), + v.transform( + (input: string | MemoryBlock32) => v.parse(hex32Schema, input) as IotaMessageId, + ), ) /** @@ -133,7 +175,8 @@ export const amountSchema = v.pipe( /** * type guard for gradido amount * create with `v.parse(gradidoAmountSchema, '123')` - * gradido amount is a string representing a positive decimal number, compatible with decimal.js + * gradido amount is a GradidoUnit representing a positive gradido amount stored intern as integer with 4 decimal places + * GradidoUnit is native implemented in gradido-blockchain-js in c++ and has functions for decay calculation */ declare const validGradidoAmount: unique symbol export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true }; diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts new file mode 100644 index 000000000..b9bd3c06c --- /dev/null +++ b/dlt-connector/src/server/index.ts @@ -0,0 +1,77 @@ +import { initTRPC, TRPCError } from '@trpc/server' +import * as v from 'valibot' +import { identifierAccountSchema } from '../schemas/account.schema' +import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' +import { getAddressType } from '../client/GradidoNode/api' +import { Uuidv4Hash } from '../data/Uuidv4Hash' +import { hex32Schema } from '../schemas/typeGuard.schema' +import { AddressType_NONE } from 'gradido-blockchain-js' + +export const t = initTRPC.create() +const publicProcedure = t.procedure +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) + +export const appRouter = t.router({ + isAccountExist: publicProcedure + .input(identifierAccountSchema) + .output(v.boolean()) + .query(async ({ input: userIdentifier }) => { + const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(userIdentifier)) + const publicKey = accountKeyPair.getPublicKey() + if (!publicKey) { + throw new TRPCError({ + code: 'NOT_FOUND', + message: "couldn't calculate account key pair", + }) + } + + // ask gradido node server for account type, if type !== NONE account exist + const addressType = await getAddressType( + v.parse(hex32Schema, publicKey.get()), + new Uuidv4Hash(userIdentifier.communityUuid), + ) + logger.info('isAccountExist') + if(logger.isDebugEnabled()) { + logger.debug('params', userIdentifier) + } + return addressType !== AddressType_NONE + }), + + sendTransaction: publicProcedure + .input(transactionDraftSchema) + .output(v.instanceof(TransactionResult)) + .mutation(async ({ input: transactionDraft }) => { + try { + return await SendToIotaContext(transactionDraft) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + if (error instanceof TransactionError) { + return new TransactionResult(error) + } else { + throw error + } + } + }) +}) + +/* + +async sendTransaction( + @Arg('data') + transactionDraft: TransactionDraft, + ): Promise { + try { + return await SendToIotaContext(transactionDraft) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + if (error instanceof TransactionError) { + return new TransactionResult(error) + } else { + throw error + } + } + } + */ \ No newline at end of file diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts new file mode 100644 index 000000000..a1f912581 --- /dev/null +++ b/dlt-connector/src/utils/typeConverter.ts @@ -0,0 +1,72 @@ +import { + ConfirmedTransaction, + MemoryBlock, + InteractionDeserialize, + DeserializeType_CONFIRMED_TRANSACTION, + AddressType_COMMUNITY_AUF, + AddressType_COMMUNITY_GMW, + AddressType_COMMUNITY_HUMAN, + AddressType_COMMUNITY_PROJECT, + AddressType_CRYPTO_ACCOUNT, + AddressType_SUBACCOUNT, + AddressType_DEFERRED_TRANSFER, + AddressType_NONE, + AddressType, +} from 'gradido-blockchain-js' +import { AccountType } from '../enum/AccountType' + +export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { + const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64)) + const deserializer = new InteractionDeserialize( + confirmedTransactionBinaryPtr, + DeserializeType_CONFIRMED_TRANSACTION, + ) + deserializer.run() + const confirmedTransaction = deserializer.getConfirmedTransaction() + if (!confirmedTransaction) { + throw new Error("invalid data, couldn't deserialize") + } + return confirmedTransaction +} + +/** + * AddressType is defined in gradido-blockchain C++ Code + * AccountType is the enum defined in TypeScript but with the same options + */ +const accountToAddressMap: Record = { + [AccountType.COMMUNITY_AUF]: AddressType_COMMUNITY_AUF, + [AccountType.COMMUNITY_GMW]: AddressType_COMMUNITY_GMW, + [AccountType.COMMUNITY_HUMAN]: AddressType_COMMUNITY_HUMAN, + [AccountType.COMMUNITY_PROJECT]: AddressType_COMMUNITY_PROJECT, + [AccountType.CRYPTO_ACCOUNT]: AddressType_CRYPTO_ACCOUNT, + [AccountType.SUBACCOUNT]: AddressType_SUBACCOUNT, + [AccountType.DEFERRED_TRANSFER]: AddressType_DEFERRED_TRANSFER, + [AccountType.NONE]: AddressType_NONE, +} + +const addressToAccountMap: Record = Object.entries(accountToAddressMap).reduce((acc, [accKey, addrVal]) => { + acc[addrVal] = String(accKey) as AccountType + return acc; +}, {} as Record) + +export function isAddressType(val: unknown): val is AddressType { + return typeof val === 'number' && Object.keys(addressToAccountMap).includes(val.toString()) +} + +export function isAccountType(val: unknown): val is AccountType { + return Object.values(AccountType).includes(val as AccountType); +} + +export function toAddressType(input: AccountType | AddressType): AddressType { + if (isAddressType(input)) { + return input + } + return accountToAddressMap[input as AccountType] ?? AddressType_NONE +} + +export function toAccountType(input: AccountType | AddressType): AccountType { + if (isAccountType(input)) { + return input + } + return addressToAccountMap[input as AddressType] ?? AccountType.NONE +} From eb29dde8c3a8950601347b9dad393f15b828742e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 16 Aug 2025 16:38:41 +0200 Subject: [PATCH 026/226] finalize refactoring, change for using hiero instead of iota --- dlt-connector/biome.json | 154 +++ dlt-connector/bun.lock | 923 +++++++++++++++++- dlt-connector/package.json | 10 +- dlt-connector/src/KeyPairCacheManager.ts | 21 +- dlt-connector/src/client/GradidoNode/api.ts | 73 +- .../src/client/GradidoNode/input.schema.ts | 21 +- .../src/client/GradidoNode/jsonrpc.ts | 22 +- dlt-connector/src/client/HieroClient.ts | 74 ++ .../src/client/backend/BackendClient.ts | 25 +- .../client/backend/community.schema.test.ts | 26 +- .../src/client/backend/community.schema.ts | 16 +- dlt-connector/src/config/index.ts | 13 +- dlt-connector/src/config/schema.ts | 24 + .../src/data/KeyPairIdentifier.logic.ts | 45 +- dlt-connector/src/data/Uuidv4Hash.ts | 17 +- dlt-connector/src/enum/AddressType.ts | 4 +- .../src/enum/GradidoNodeErrorCodes.ts | 2 +- .../src/enum/InputTransactionType.ts | 22 +- dlt-connector/src/errors.ts | 2 +- dlt-connector/src/index.ts | 37 +- .../AbstractRemoteKeyPair.role.ts | 9 +- .../keyPairCalculation/AccountKeyPair.role.ts | 5 +- .../ForeignCommunityKeyPair.role.ts | 21 +- .../KeyPairCalculation.context.ts | 14 +- .../LinkedTransactionKeyPair.role.ts | 7 +- .../RemoteAccountKeyPair.role.ts | 13 +- .../keyPairCalculation/UserKeyPair.role.ts | 5 +- .../UserKeyPairRole.test.ts | 64 ++ .../sendToIota/AbstractTransaction.role.ts | 5 +- .../CommunityRootTransaction.role.ts | 26 +- .../sendToIota/CreationTransaction.role.ts | 75 +- .../DeferredTransferTransaction.role.ts | 53 +- .../RedeemDeferredTransferTransaction.role.ts | 91 +- .../RegisterAddressTransaction.role.ts | 77 +- .../sendToIota/SendToIota.context.ts | 145 ++- .../sendToIota/TransferTransaction.role.ts | 45 +- dlt-connector/src/schemas/account.schema.ts | 11 +- dlt-connector/src/schemas/base.schema.ts | 8 +- .../src/schemas/transaction.schema.test.ts | 295 +++--- .../src/schemas/transaction.schema.ts | 94 +- .../src/schemas/typeConverter.schema.test.ts | 19 +- .../src/schemas/typeConverter.schema.ts | 29 +- .../src/schemas/typeGuard.schema.test.ts | 14 +- dlt-connector/src/schemas/typeGuard.schema.ts | 154 +-- dlt-connector/src/server/index.ts | 142 ++- dlt-connector/src/server/input.schema.ts | 19 + .../src/utils/derivationHelper.test.ts | 2 +- dlt-connector/src/utils/network.ts | 16 +- dlt-connector/src/utils/typeConverter.ts | 29 +- 49 files changed, 2146 insertions(+), 872 deletions(-) create mode 100644 dlt-connector/biome.json create mode 100644 dlt-connector/src/client/HieroClient.ts create mode 100644 dlt-connector/src/config/schema.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts create mode 100644 dlt-connector/src/server/input.schema.ts diff --git a/dlt-connector/biome.json b/dlt-connector/biome.json new file mode 100644 index 000000000..3ec5af1be --- /dev/null +++ b/dlt-connector/biome.json @@ -0,0 +1,154 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, + "files": { + "ignoreUnknown": false, + "includes": [ + "**/package.json", + "src/**/*.js", + "src/**/*.ts", + "!**/build", + "!**/node_modules", + "!**/coverage" + ] + }, + "formatter": { + "enabled": true, + "useEditorconfig": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 100, + "attributePosition": "auto", + "bracketSpacing": true + }, + "assist": { "actions": { "source": { "organizeImports": "on" } } }, + "linter": { + "enabled": true, + "rules": { + "recommended": false, + "complexity": { + "noExtraBooleanCast": "error", + "noUselessCatch": "error", + "noUselessConstructor": "error", + "noUselessLoneBlockStatements": "error", + "noUselessRename": "error", + "noUselessTernary": "error", + "noUselessUndefinedInitialization": "error", + "noVoid": "error", + "useLiteralKeys": "error", + "useRegexLiterals": "error", + "noAdjacentSpacesInRegex": "error", + "noCommaOperator": "error" + }, + "correctness": { + "noConstAssign": "error", + "noConstantCondition": "error", + "noEmptyCharacterClassInRegex": "error", + "noEmptyPattern": "error", + "noGlobalObjectCalls": "error", + "noInnerDeclarations": "error", + "noInvalidConstructorSuper": "error", + "noInvalidUseBeforeDeclaration": "error", + "noNodejsModules": "off", + "noNonoctalDecimalEscape": "error", + "noPrecisionLoss": "error", + "noSelfAssign": "error", + "noSetterReturn": "error", + "noSwitchDeclarations": "error", + "noUndeclaredVariables": "error", + "noUnreachable": "error", + "noUnreachableSuper": "error", + "noUnsafeFinally": "error", + "noUnsafeOptionalChaining": "error", + "noUnusedLabels": "error", + "noUnusedVariables": "error", + "useIsNan": "error", + "useValidForDirection": "error", + "useYield": "error", + "noInvalidBuiltinInstantiation": "error", + "useValidTypeof": "error" + }, + "security": { "noGlobalEval": "error" }, + "style": { + "noDefaultExport": "error", + "noYodaExpression": "error", + "useBlockStatements": "error", + "useConsistentBuiltinInstantiation": "error", + "useConst": "error", + "useImportType": "off", + "useSingleVarDeclarator": "error", + "useArrayLiterals": "error" + }, + "suspicious": { + "noAsyncPromiseExecutor": "error", + "noCatchAssign": "error", + "noClassAssign": "error", + "noCompareNegZero": "error", + "noConsole": "error", + "noControlCharactersInRegex": "error", + "noDebugger": "error", + "noDoubleEquals": "error", + "noDuplicateCase": "error", + "noDuplicateClassMembers": "error", + "noDuplicateObjectKeys": "error", + "noDuplicateParameters": "error", + "noEmptyBlockStatements": "error", + "noFallthroughSwitchClause": "error", + "noFunctionAssign": "error", + "noGlobalAssign": "error", + "noImportAssign": "error", + "noMisleadingCharacterClass": "error", + "noPrototypeBuiltins": "error", + "noRedeclare": "error", + "noSelfCompare": "error", + "noShadowRestrictedNames": "error", + "noSparseArray": "error", + "noUnsafeNegation": "error", + "useDefaultSwitchClauseLast": "error", + "useGetterReturn": "error", + "noWith": "error", + "noVar": "warn" + } + }, + "includes": ["**", "!**/node_modules", "!**/*.min.js", "!**/build", "!**/coverage"] + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "single", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "asNeeded", + "arrowParentheses": "always", + "bracketSameLine": false, + "quoteStyle": "single", + "attributePosition": "auto", + "bracketSpacing": true + }, + "globals": [ + "document", + "navigator", + "window", + "describe", + "test", + "it", + "expect", + "beforeAll", + "beforeEach", + "afterAll", + "afterEach", + "jest" + ], + "parser": { + "unsafeParameterDecoratorsEnabled": true + } + }, + "overrides": [ + { + "includes": ["**/*.ts", "**/*.tsx"], + "linter": { "rules": { "complexity": { "noVoid": "error" } } } + }, + { "includes": ["**/*.test.ts"], "linter": { "rules": {} } } + ] +} diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 2d3860900..5795142a4 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -11,10 +11,13 @@ "@biomejs/biome": "2.0.0", "@elysiajs/trpc": "^1.1.0", "@elysiajs/websocket": "^0.2.8", + "@hashgraph/sdk": "^2.70.0", + "@sinclair/typebox": "^0.34.33", + "@sinclair/typemap": "^0.10.1", "@trpc/server": "^11.4.3", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", - "elysia": "^1.3.5", + "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", @@ -30,6 +33,176 @@ "@iota/client", ], "packages": { + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + + "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + + "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], + + "@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="], + + "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], + + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg=="], + + "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ=="], + + "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], + + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], + + "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="], + + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="], + + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="], + + "@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="], + + "@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + + "@babel/plugin-proposal-export-default-from": ["@babel/plugin-proposal-export-default-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw=="], + + "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], + + "@babel/plugin-syntax-bigint": ["@babel/plugin-syntax-bigint@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg=="], + + "@babel/plugin-syntax-class-properties": ["@babel/plugin-syntax-class-properties@7.12.13", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA=="], + + "@babel/plugin-syntax-class-static-block": ["@babel/plugin-syntax-class-static-block@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw=="], + + "@babel/plugin-syntax-dynamic-import": ["@babel/plugin-syntax-dynamic-import@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="], + + "@babel/plugin-syntax-export-default-from": ["@babel/plugin-syntax-export-default-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg=="], + + "@babel/plugin-syntax-flow": ["@babel/plugin-syntax-flow@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA=="], + + "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww=="], + + "@babel/plugin-syntax-import-meta": ["@babel/plugin-syntax-import-meta@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g=="], + + "@babel/plugin-syntax-json-strings": ["@babel/plugin-syntax-json-strings@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], + + "@babel/plugin-syntax-logical-assignment-operators": ["@babel/plugin-syntax-logical-assignment-operators@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig=="], + + "@babel/plugin-syntax-nullish-coalescing-operator": ["@babel/plugin-syntax-nullish-coalescing-operator@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="], + + "@babel/plugin-syntax-numeric-separator": ["@babel/plugin-syntax-numeric-separator@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug=="], + + "@babel/plugin-syntax-object-rest-spread": ["@babel/plugin-syntax-object-rest-spread@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA=="], + + "@babel/plugin-syntax-optional-catch-binding": ["@babel/plugin-syntax-optional-catch-binding@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q=="], + + "@babel/plugin-syntax-optional-chaining": ["@babel/plugin-syntax-optional-chaining@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg=="], + + "@babel/plugin-syntax-private-property-in-object": ["@babel/plugin-syntax-private-property-in-object@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg=="], + + "@babel/plugin-syntax-top-level-await": ["@babel/plugin-syntax-top-level-await@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], + + "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], + + "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="], + + "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="], + + "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q=="], + + "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], + + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg=="], + + "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="], + + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A=="], + + "@babel/plugin-transform-flow-strip-types": ["@babel/plugin-transform-flow-strip-types@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-flow": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg=="], + + "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], + + "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="], + + "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], + + "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw=="], + + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="], + + "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="], + + "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="], + + "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="], + + "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA=="], + + "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="], + + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="], + + "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], + + "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="], + + "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="], + + "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="], + + "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], + + "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A=="], + + "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg=="], + + "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], + + "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="], + + "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="], + + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg=="], + + "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], + + "@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="], + + "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], + + "@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + + "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + + "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], + "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], @@ -48,25 +221,193 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], + "@elysiajs/trpc": ["@elysiajs/trpc@1.1.0", "", { "peerDependencies": { "elysia": ">= 1.1.0" } }, "sha512-M8QWC+Wa5Z5MWY/+uMQuwZ+JoQkp4jOc1ra4SncFy1zSjFGin59LO1AT0pE+DRJaFV17gha9y7cB6Q7GnaJEAw=="], "@elysiajs/websocket": ["@elysiajs/websocket@0.2.8", "", { "dependencies": { "nanoid": "^4.0.0", "raikiri": "^0.0.0-beta.3" }, "peerDependencies": { "elysia": ">= 0.2.2" } }, "sha512-K9KLmYL1SYuAV353GvmK0V9DG5w7XTOGsa1H1dGB5BUTzvBaMvnwNeqnJQ3cjf9V1c0EjQds0Ty4LfUFvV45jw=="], + "@ethersproject/abi": ["@ethersproject/abi@5.8.0", "", { "dependencies": { "@ethersproject/address": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/constants": "^5.8.0", "@ethersproject/hash": "^5.8.0", "@ethersproject/keccak256": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/strings": "^5.8.0" } }, "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q=="], + + "@ethersproject/abstract-provider": ["@ethersproject/abstract-provider@5.8.0", "", { "dependencies": { "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/networks": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/transactions": "^5.8.0", "@ethersproject/web": "^5.8.0" } }, "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg=="], + + "@ethersproject/abstract-signer": ["@ethersproject/abstract-signer@5.8.0", "", { "dependencies": { "@ethersproject/abstract-provider": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0" } }, "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA=="], + + "@ethersproject/address": ["@ethersproject/address@5.8.0", "", { "dependencies": { "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/keccak256": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/rlp": "^5.8.0" } }, "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA=="], + + "@ethersproject/base64": ["@ethersproject/base64@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0" } }, "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ=="], + + "@ethersproject/bignumber": ["@ethersproject/bignumber@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "bn.js": "^5.2.1" } }, "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA=="], + + "@ethersproject/bytes": ["@ethersproject/bytes@5.8.0", "", { "dependencies": { "@ethersproject/logger": "^5.8.0" } }, "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A=="], + + "@ethersproject/constants": ["@ethersproject/constants@5.8.0", "", { "dependencies": { "@ethersproject/bignumber": "^5.8.0" } }, "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg=="], + + "@ethersproject/hash": ["@ethersproject/hash@5.8.0", "", { "dependencies": { "@ethersproject/abstract-signer": "^5.8.0", "@ethersproject/address": "^5.8.0", "@ethersproject/base64": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/keccak256": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/strings": "^5.8.0" } }, "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA=="], + + "@ethersproject/keccak256": ["@ethersproject/keccak256@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "js-sha3": "0.8.0" } }, "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng=="], + + "@ethersproject/logger": ["@ethersproject/logger@5.8.0", "", {}, "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA=="], + + "@ethersproject/networks": ["@ethersproject/networks@5.8.0", "", { "dependencies": { "@ethersproject/logger": "^5.8.0" } }, "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg=="], + + "@ethersproject/properties": ["@ethersproject/properties@5.8.0", "", { "dependencies": { "@ethersproject/logger": "^5.8.0" } }, "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw=="], + + "@ethersproject/rlp": ["@ethersproject/rlp@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0" } }, "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q=="], + + "@ethersproject/signing-key": ["@ethersproject/signing-key@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "bn.js": "^5.2.1", "elliptic": "6.6.1", "hash.js": "1.1.7" } }, "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w=="], + + "@ethersproject/strings": ["@ethersproject/strings@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "@ethersproject/constants": "^5.8.0", "@ethersproject/logger": "^5.8.0" } }, "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg=="], + + "@ethersproject/transactions": ["@ethersproject/transactions@5.8.0", "", { "dependencies": { "@ethersproject/address": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/constants": "^5.8.0", "@ethersproject/keccak256": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@ethersproject/signing-key": "^5.8.0" } }, "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg=="], + + "@ethersproject/web": ["@ethersproject/web@5.8.0", "", { "dependencies": { "@ethersproject/base64": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/strings": "^5.8.0" } }, "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw=="], + "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], + "@grpc/grpc-js": ["@grpc/grpc-js@1.13.4", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg=="], + + "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], + + "@hashgraph/cryptography": ["@hashgraph/cryptography@1.9.0", "", { "dependencies": { "@noble/curves": "^1.8.1", "asn1js": "^3.0.6", "bignumber.js": "^9.1.1", "bn.js": "^5.2.1", "buffer": "^6.0.3", "crypto-js": "^4.2.0", "forge-light": "1.1.4", "js-base64": "^3.7.7", "react-native-get-random-values": "^1.11.0", "spark-md5": "^3.0.2", "tweetnacl": "^1.0.3", "utf8": "^3.0.0" } }, "sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg=="], + + "@hashgraph/proto": ["@hashgraph/proto@2.20.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "7.2.5" } }, "sha512-XGIHRE9jr4wnnmCG8JeUD/nyeCiiYoUt35oRJz0QdCUwJYtbEsR6tPQxO90PxJJVDI5smT1c5i0f9wRRtFDhIA=="], + + "@hashgraph/sdk": ["@hashgraph/sdk@2.70.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.20.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-naml5lWgewD3Dh8z0K7NRuKpbOpDaxpxwcLjtB9RFVmATMDU3IShSzxy24k5tUgY/0ZE7XXfCKgIpdT7TxGKqQ=="], + "@iota/client": ["@iota/client@2.2.4", "", { "dependencies": { "neon-cli": "^0.8", "prebuild-install": "^6.1.2" } }, "sha512-6zjtqJgkSgrMUFLbxr9k+zXGnEVw6gjTFn5emN2nKpR78+mwW4jUXuNcy/M194bK4sLHjj0T0L4pRWJ6XTGaew=="], - "@sinclair/typebox": ["@sinclair/typebox@0.34.37", "", {}, "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw=="], + "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], + + "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], + + "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], + + "@jest/create-cache-key-function": ["@jest/create-cache-key-function@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3" } }, "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA=="], + + "@jest/environment": ["@jest/environment@29.7.0", "", { "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" } }, "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw=="], + + "@jest/fake-timers": ["@jest/fake-timers@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", "jest-message-util": "^29.7.0", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ=="], + + "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + + "@jest/transform": ["@jest/transform@29.7.0", "", { "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.2" } }, "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw=="], + + "@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], + + "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + + "@noble/curves": ["@noble/curves@1.9.6", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + + "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + + "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + + "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + + "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + + "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + + "@react-native/assets-registry": ["@react-native/assets-registry@0.81.0", "", {}, "sha512-rZs8ziQ1YRV3Z5Mw5AR7YcgI3q1Ya9NIx6nyuZAT9wDSSjspSi+bww+Hargh/a4JfV2Ajcxpn9X9UiFJr1ddPw=="], + + "@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.81.0", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.81.0" } }, "sha512-MEMlW91+2Kk9GiObRP1Nc6oTdiyvmSEbPMSC6kzUzDyouxnh5/x28uyNySmB2nb6ivcbmQ0lxaU059+CZSkKXQ=="], + + "@react-native/babel-preset": ["@react-native/babel-preset@0.81.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.81.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-RKMgCUGsso/2b32kgg24lB68LJ6qr2geLoSQTbisY6Usye0uXeXCgbZZDbILIX9upL4uzU4staMldRZ0v08F1g=="], + + "@react-native/codegen": ["@react-native/codegen@0.81.0", "", { "dependencies": { "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, "peerDependencies": { "@babel/core": "*" } }, "sha512-gPFutgtj8YqbwKKt3YpZKamUBGd9YZJV51Jq2aiDZ9oThkg1frUBa20E+Jdi7jKn982wjBMxAklAR85QGQ4xMA=="], + + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.0", "", { "dependencies": { "@react-native/dev-middleware": "0.81.0", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli"] }, "sha512-n04ACkCaLR54NmA/eWiDpjC16pHr7+yrbjQ6OEdRoXbm5EfL8FEre2kDAci7pfFdiSMpxdRULDlKpfQ+EV/GAQ=="], + + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.0", "", {}, "sha512-N/8uL2CGQfwiQRYFUNfmaYxRDSoSeOmFb56rb0PDnP3XbS5+X9ee7X4bdnukNHLGfkRdH7sVjlB8M5zE8XJOhw=="], + + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.0", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.0", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-J/HeC/+VgRyGECPPr9rAbe5S0OL6MCIrvrC/kgNKSME5+ZQLCiTpt3pdAoAMXwXiF9a02Nmido0DnyM1acXTIA=="], + + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.0", "", {}, "sha512-LGNtPXO1RKLws5ORRb4Q4YULi2qxM4qZRuARtwqM/1f2wyZVggqapoV0OXlaXaz+GiEd2ll3ROE4CcLN6J93jg=="], + + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.0", "", {}, "sha512-whXZWIogzoGpqdyTjqT89M6DXmlOkWqNpWoVOAwVi8XFCMO+L7WTk604okIgO6gdGZcP1YtFpQf9JusbKrv/XA=="], + + "@react-native/metro-babel-transformer": ["@react-native/metro-babel-transformer@0.81.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@react-native/babel-preset": "0.81.0", "hermes-parser": "0.29.1", "nullthrows": "^1.1.1" } }, "sha512-Mwovr4jJ3JTnbHEQLhdcMvS82LjijpqCydXl1aH2N16WVCrE5oSNFiqTt6NpZBw9zkJX7nijsY+xeCy6m+KK3Q=="], + + "@react-native/metro-config": ["@react-native/metro-config@0.81.0", "", { "dependencies": { "@react-native/js-polyfills": "0.81.0", "@react-native/metro-babel-transformer": "0.81.0", "metro-config": "^0.83.1", "metro-runtime": "^0.83.1" } }, "sha512-5eqLP4TCERHGRYDJSZa//O98CGDFNNEwHVvhs65Msfy6hAoSdw5pAAuTrsQwmbTBp0Fkvu7Bx8BZDhiferZsHg=="], + + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.0", "", {}, "sha512-3gEu/29uFgz+81hpUgdlOojM4rjHTIPwxpfygFNY60V6ywZih3eLDTS8kAjNZfPFHQbcYrNorJzwnL5yFF/uLw=="], + + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.0", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-p14QC5INHkbMZ96158sUxkSwN6zp138W11G+CRGoLJY4Q9WRJBCe7wHR5Owyy3XczQXrIih/vxAXwgYeZ2XByg=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.39", "", {}, "sha512-keEoFsevmLwAedzacnTVmra66GViRH3fhWO1M+nZ8rUgpPJyN4mcvqlGr3QMrQXx4L8KNwW0q9/BeHSEoO4teg=="], + + "@sinclair/typemap": ["@sinclair/typemap@0.10.1", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.30", "valibot": "^1.0.0", "zod": "^3.24.1" } }, "sha512-UXR0fhu/n3c9B6lB+SLI5t1eVpt9i9CdDrp2TajRe3LbKiUhCTZN2kSfJhjPnpc3I59jMRIhgew7+0HlMi08mg=="], + + "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="], "@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="], "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], - "@trpc/server": ["@trpc/server@11.4.3", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-wnWq3wiLlMOlYkaIZz+qbuYA5udPTLS4GVVRyFkr6aT83xpdCHyVtURT+u4hSoIrOXQM9OPCNXSXsAujWZDdaw=="], + "@trpc/server": ["@trpc/server@11.4.4", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-VkJb2xnb4rCynuwlCvgPBh5aM+Dco6fBBIo6lWAdJJRYVwtyE5bxNZBgUvRRz/cFSEAy0vmzLxF7aABDJfK5Rg=="], - "@types/bun": ["@types/bun@1.2.17", "", { "dependencies": { "bun-types": "1.2.17" } }, "sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], - "@types/node": ["@types/node@24.0.7", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw=="], + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], + + "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="], + + "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="], + + "@types/istanbul-lib-report": ["@types/istanbul-lib-report@3.0.3", "", { "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA=="], + + "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], + + "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], + + "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="], + + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], + + "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], @@ -74,40 +415,102 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="], "are-we-there-yet": ["are-we-there-yet@1.1.7", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g=="], + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "array-back": ["array-back@3.1.0", "", {}, "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="], + "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], + + "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="], + + "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "axios": ["axios@0.24.0", "", { "dependencies": { "follow-redirects": "^1.14.4" } }, "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA=="], + "babel-jest": ["babel-jest@29.7.0", "", { "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg=="], + + "babel-plugin-istanbul": ["babel-plugin-istanbul@6.1.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" } }, "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA=="], + + "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@29.6.3", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg=="], + + "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="], + + "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="], + + "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="], + + "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], + + "babel-plugin-transform-flow-enums": ["babel-plugin-transform-flow-enums@0.0.2", "", { "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" } }, "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ=="], + + "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], + + "babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + "bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="], + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "brorand": ["brorand@1.1.0", "", {}, "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="], + + "browserslist": ["browserslist@4.25.2", "", { "dependencies": { "caniuse-lite": "^1.0.30001733", "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA=="], + + "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], + + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "builtins": ["builtins@1.0.3", "", {}, "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="], - "bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="], + "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + "caller-callsite": ["caller-callsite@2.0.0", "", { "dependencies": { "callsites": "^2.0.0" } }, "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ=="], + + "caller-path": ["caller-path@2.0.0", "", { "dependencies": { "caller-callsite": "^2.0.0" } }, "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A=="], + + "callsites": ["callsites@2.0.0", "", {}, "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ=="], + + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001735", "", {}, "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + "chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="], + + "chromium-edge-launcher": ["chromium-edge-launcher@0.2.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg=="], + + "ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], "cli-width": ["cli-width@3.0.0", "", {}, "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="], @@ -124,6 +527,8 @@ "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], "command-line-args": ["command-line-args@5.2.1", "", { "dependencies": { "array-back": "^3.1.0", "find-replace": "^3.0.0", "lodash.camelcase": "^4.3.0", "typical": "^4.0.0" } }, "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg=="], @@ -136,14 +541,28 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "connect": ["connect@3.7.0", "", { "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", "parseurl": "~1.3.3", "utils-merge": "1.0.1" } }, "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ=="], + "console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + "core-js-compat": ["core-js-compat@3.45.0", "", { "dependencies": { "browserslist": "^4.25.1" } }, "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA=="], + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "cosmiconfig": ["cosmiconfig@5.2.1", "", { "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA=="], + + "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], + "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], "decompress-response": ["decompress-response@4.2.1", "", { "dependencies": { "mimic-response": "^2.0.0" } }, "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw=="], @@ -154,18 +573,34 @@ "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "dotenv": ["dotenv@10.0.0", "", {}, "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "elysia": ["elysia@1.3.5", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-XVIKXlKFwUT7Sta8GY+wO5reD9I0rqAEtaz1Z71UgJb61csYt8Q3W9al8rtL5RgumuRR8e3DNdzlUN9GkC4KDw=="], + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.202", "", {}, "sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg=="], + + "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], + + "elysia": ["elysia@1.3.8", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.3", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-kxYFhegJbUEf5otzmisEvGt3R7d/dPBNVERO2nHo0kFqKBHyj5slArc90mSRKLfi1vamMtPcz67rL6Zeg5F2yg=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], + + "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], @@ -176,18 +611,40 @@ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], - "exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "exact-mirror": ["exact-mirror@0.1.3", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-yI62LpSby0ItzPJF05C4DRycVAoknRiCIDOLOCCs9zaEKylOXQtOFM3flX54S44swpRz584vk3P70yWQodsLlg=="], "execspawn": ["execspawn@1.0.1", "", { "dependencies": { "util-extend": "^1.0.1" } }, "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg=="], "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], + "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], + "fast-base64-decode": ["fast-base64-decode@1.0.0", "", {}, "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="], + + "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], + + "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + + "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], @@ -196,13 +653,25 @@ "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@1.1.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" } }, "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="], + "find-replace": ["find-replace@3.0.0", "", { "dependencies": { "array-back": "^3.0.1" } }, "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ=="], + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], + "flow-enums-runtime": ["flow-enums-runtime@0.0.6", "", {}, "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw=="], - "form-data": ["form-data@4.0.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA=="], + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + + "forge-light": ["forge-light@1.1.4", "", {}, "sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g=="], + + "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], @@ -212,14 +681,20 @@ "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "gauge": ["gauge@2.7.4", "", { "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.0", "object-assign": "^4.1.0", "signal-exit": "^3.0.0", "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" } }, "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], "git-config": ["git-config@0.0.7", "", { "dependencies": { "iniparser": "~1.0.5" } }, "sha512-LidZlYZXWzVjS+M3TEwhtYBaYwLeOZrXci1tBgqp/vDdZTBMl02atvwb6G35L64ibscYoPnxfbwwUS+VZAISLA=="], @@ -248,12 +723,32 @@ "has-unicode": ["has-unicode@2.0.1", "", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="], + "hash.js": ["hash.js@1.1.7", "", { "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], + + "hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="], + + "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="], + + "hmac-drbg": ["hmac-drbg@1.0.1", "", { "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], + + "import-fresh": ["import-fresh@2.0.0", "", { "dependencies": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" } }, "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], @@ -264,30 +759,140 @@ "inquirer": ["inquirer@7.3.3", "", { "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" } }, "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA=="], + "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-directory": ["is-directory@0.3.1", "", {}, "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], + + "istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], + + "jest-environment-node": ["jest-environment-node@29.7.0", "", { "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw=="], + + "jest-get-type": ["jest-get-type@29.6.3", "", {}, "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw=="], + + "jest-haste-map": ["jest-haste-map@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA=="], + + "jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="], + + "jest-mock": ["jest-mock@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "jest-util": "^29.7.0" } }, "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw=="], + + "jest-regex-util": ["jest-regex-util@29.6.3", "", {}, "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg=="], + + "jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="], + + "jest-validate": ["jest-validate@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", "pretty-format": "^29.7.0" } }, "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw=="], + + "jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + + "js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="], + + "js-sha3": ["js-sha3@0.8.0", "", {}, "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + + "jsc-safe-url": ["jsc-safe-url@0.2.4", "", {}, "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "jsonrpc-ts-client": ["jsonrpc-ts-client@0.2.3", "", { "dependencies": { "axios": "^0.24.0", "debug": "^4.3.3" } }, "sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g=="], + "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], + + "lighthouse-logger": ["lighthouse-logger@1.4.2", "", { "dependencies": { "debug": "^2.6.9", "marky": "^1.2.2" } }, "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g=="], + + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], + + "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="], + "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "make-promises-safe": ["make-promises-safe@5.1.0", "", {}, "sha512-AfdZ49rtyhQR/6cqVKGoH7y4ql7XkS5HJI1lZm0/5N6CQosy1eYbBJ/qbhkKHzo17UH7M918Bysf6XB9f3kS1g=="], + "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], + + "marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "memoize-one": ["memoize-one@5.2.1", "", {}, "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="], + "memory-stream": ["memory-stream@1.0.0", "", { "dependencies": { "readable-stream": "^3.4.0" } }, "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww=="], + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "metro": ["metro@0.83.1", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.29.1", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-config": "0.83.1", "metro-core": "0.83.1", "metro-file-map": "0.83.1", "metro-resolver": "0.83.1", "metro-runtime": "0.83.1", "metro-source-map": "0.83.1", "metro-symbolicate": "0.83.1", "metro-transform-plugins": "0.83.1", "metro-transform-worker": "0.83.1", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-UGKepmTxoGD4HkQV8YWvpvwef7fUujNtTgG4Ygf7m/M0qjvb9VuDmAsEU+UdriRX7F61pnVK/opz89hjKlYTXA=="], + + "metro-babel-transformer": ["metro-babel-transformer@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.29.1", "nullthrows": "^1.1.1" } }, "sha512-r3xAD3964E8dwDBaZNSO2aIIvWXjIK80uO2xo0/pi3WI8XWT9h5SCjtGWtMtE5PRWw+t20TN0q1WMRsjvhC1rQ=="], + + "metro-cache": ["metro-cache@0.83.1", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.1" } }, "sha512-7N/Ad1PHa1YMWDNiyynTPq34Op2qIE68NWryGEQ4TSE3Zy6a8GpsYnEEZE4Qi6aHgsE+yZHKkRczeBgxhnFIxQ=="], + + "metro-cache-key": ["metro-cache-key@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ZUs+GD5CNeDLxx5UUWmfg26IL+Dnbryd+TLqTlZnDEgehkIa11kUSvgF92OFfJhONeXzV4rZDRGNXoo6JT+8Gg=="], + + "metro-config": ["metro-config@0.83.1", "", { "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.1", "metro-cache": "0.83.1", "metro-core": "0.83.1", "metro-runtime": "0.83.1" } }, "sha512-HJhpZx3wyOkux/jeF1o7akFJzZFdbn6Zf7UQqWrvp7gqFqNulQ8Mju09raBgPmmSxKDl4LbbNeigkX0/nKY1QA=="], + + "metro-core": ["metro-core@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.1" } }, "sha512-uVL1eAJcMFd2o2Q7dsbpg8COaxjZBBGaXqO2OHnivpCdfanraVL8dPmY6It9ZeqWLOihUKZ2yHW4b6soVCzH/Q=="], + + "metro-file-map": ["metro-file-map@0.83.1", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-Yu429lnexKl44PttKw3nhqgmpBR+6UQ/tRaYcxPeEShtcza9DWakCn7cjqDTQZtWR2A8xSNv139izJMyQ4CG+w=="], + + "metro-minify-terser": ["metro-minify-terser@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-kmooOxXLvKVxkh80IVSYO4weBdJDhCpg5NSPkjzzAnPJP43u6+usGXobkTWxxrAlq900bhzqKek4pBsUchlX6A=="], + + "metro-resolver": ["metro-resolver@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-t8j46kiILAqqFS5RNa+xpQyVjULxRxlvMidqUswPEk5nQVNdlJslqizDm/Et3v/JKwOtQGkYAQCHxP1zGStR/g=="], + + "metro-runtime": ["metro-runtime@0.83.1", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-3Ag8ZS4IwafL/JUKlaeM6/CbkooY+WcVeqdNlBG0m4S0Qz0om3rdFdy1y6fYBpl6AwXJwWeMuXrvZdMuByTcRA=="], + + "metro-source-map": ["metro-source-map@0.83.1", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.1", "nullthrows": "^1.1.1", "ob1": "0.83.1", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-De7Vbeo96fFZ2cqmI0fWwVJbtHIwPZv++LYlWSwzTiCzxBDJORncN0LcT48Vi2UlQLzXJg+/CuTAcy7NBVh69A=="], + + "metro-symbolicate": ["metro-symbolicate@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.1", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-wPxYkONlq/Sv8Ji7vHEx5OzFouXAMQJjpcPW41ySKMLP/Ir18SsiJK2h4YkdKpYrTS1+0xf8oqF6nxCsT3uWtg=="], + + "metro-transform-plugins": ["metro-transform-plugins@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-1Y+I8oozXwhuS0qwC+ezaHXBf0jXW4oeYn4X39XWbZt9X2HfjodqY9bH9r6RUTsoiK7S4j8Ni2C91bUC+sktJQ=="], + + "metro-transform-worker": ["metro-transform-worker@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-minify-terser": "0.83.1", "metro-source-map": "0.83.1", "metro-transform-plugins": "0.83.1", "nullthrows": "^1.1.1" } }, "sha512-owCrhPyUxdLgXEEEAL2b14GWTPZ2zYuab1VQXcfEy0sJE71iciD7fuMcrngoufh7e7UHDZ56q4ktXg8wgiYA1Q=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -296,6 +901,10 @@ "mimic-response": ["mimic-response@2.1.0", "", {}, "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="], + "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], + + "minimalistic-crypto-utils": ["minimalistic-crypto-utils@1.0.1", "", {}, "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="], + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -312,12 +921,14 @@ "mute-stream": ["mute-stream@0.0.8", "", {}, "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="], - "nan": ["nan@2.22.2", "", {}, "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ=="], + "nan": ["nan@2.23.0", "", {}, "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ=="], "nanoid": ["nanoid@4.0.2", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw=="], "napi-build-utils": ["napi-build-utils@1.0.2", "", {}, "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="], + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], "neon-cli": ["neon-cli@0.8.3", "", { "dependencies": { "chalk": "^4.1.0", "command-line-args": "^5.1.1", "command-line-commands": "^3.0.1", "command-line-usage": "^6.1.0", "git-config": "0.0.7", "handlebars": "^4.7.6", "inquirer": "^7.3.3", "make-promises-safe": "^5.1.0", "rimraf": "^3.0.2", "semver": "^7.3.2", "toml": "^3.0.0", "ts-typed-json": "^0.3.2", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" }, "bin": { "neon": "bin/cli.js" } }, "sha512-I44MB8PD0AEyFr/b5icR4sX1tsjdkb2T2uWEStG4Uf5C/jzalZPn7eazbQrW6KDyXNd8bc+LVuOr1v6CGTa1KQ=="], @@ -330,6 +941,12 @@ "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], + + "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "npm-path": ["npm-path@2.0.4", "", { "dependencies": { "which": "^1.2.10" }, "bin": { "npm-path": "bin/npm-path" } }, "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw=="], "npm-run-path": ["npm-run-path@3.1.0", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg=="], @@ -338,44 +955,132 @@ "npmlog": ["npmlog@4.1.2", "", { "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", "gauge": "~2.7.3", "set-blocking": "~2.0.0" } }, "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg=="], + "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], + "number-is-nan": ["number-is-nan@1.0.1", "", {}, "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="], + "ob1": ["ob1@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ngwqewtdUzFyycomdbdIhFLjePPSOt1awKMUXQ0L7iLHgWEPF3DsCerblzjzfAUHaXuvE9ccJymWQ/4PNNqvnQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + + "on-finished": ["on-finished@2.3.0", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "pino": ["pino@9.9.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ=="], + + "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], + + "pino-pretty": ["pino-pretty@13.1.1", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^5.0.2" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA=="], + + "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], + + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + "prebuild-install": ["prebuild-install@6.1.4", "", { "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^3.0.3", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ=="], "prebuildify": ["prebuildify@github:einhornimmond/prebuildify#65d9445", { "dependencies": { "cmake-js": "^7.2.1", "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", "npm-run-path": "^3.1.0", "npm-which": "^3.0.1", "pump": "^3.0.0", "tar-fs": "^2.1.0" }, "bin": { "prebuildify": "./bin.js" } }, "einhornimmond-prebuildify-65d9445"], + "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + + "promise": ["promise@8.3.0", "", { "dependencies": { "asap": "~2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="], + + "protobufjs": ["protobufjs@7.2.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A=="], + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], + + "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], + + "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], + + "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + "raikiri": ["raikiri@0.0.0-beta.8", "", {}, "sha512-cH/yfvkiGkN8IBB2MkRHikpPurTnd2sMkQ/xtGpXrp3O76P4ppcWPb+86mJaBDzKaclLnSX+9NnT79D7ifH4/w=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], + + "react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="], + + "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "react-native": ["react-native@0.81.0", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.0", "@react-native/codegen": "0.81.0", "@react-native/community-cli-plugin": "0.81.0", "@react-native/gradle-plugin": "0.81.0", "@react-native/js-polyfills": "0.81.0", "@react-native/normalize-colors": "0.81.0", "@react-native/virtualized-lists": "0.81.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-RDWhewHGsAa5uZpwIxnJNiv5tW2y6/DrQUjEBdAHPzGMwuMTshern2s4gZaWYeRU3SQguExVddCjiss9IBhxqA=="], + + "react-native-get-random-values": ["react-native-get-random-values@1.11.0", "", { "dependencies": { "fast-base64-decode": "^1.0.0" }, "peerDependencies": { "react-native": ">=0.56" } }, "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ=="], + + "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + "reduce-flatten": ["reduce-flatten@2.0.0", "", {}, "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w=="], + "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], + + "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="], + + "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], + + "regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="], + + "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], + + "regjsparser": ["regjsparser@0.12.0", "", { "dependencies": { "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "rfc4648": ["rfc4648@1.5.4", "", {}, "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg=="], + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], @@ -386,27 +1091,63 @@ "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + + "secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="], + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + + "serialize-error": ["serialize-error@2.1.0", "", {}, "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="], + + "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], "simple-get": ["simple-get@3.1.1", "", { "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "spark-md5": ["spark-md5@3.0.2", "", {}, "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="], + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], - "spdx-license-ids": ["spdx-license-ids@3.0.21", "", {}, "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg=="], + "spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], + + "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], + + "stacktrace-parser": ["stacktrace-parser@0.1.11", "", { "dependencies": { "type-fest": "^0.7.1" } }, "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg=="], + + "statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], "streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="], @@ -416,12 +1157,14 @@ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], - "strtok3": ["strtok3@10.3.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw=="], + "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "table-layout": ["table-layout@1.0.2", "", { "dependencies": { "array-back": "^4.0.1", "deep-extend": "~0.6.0", "typical": "^5.2.0", "wordwrapjs": "^4.0.0" } }, "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A=="], "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], @@ -430,40 +1173,74 @@ "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + "terser": ["terser@5.43.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="], + + "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], + + "throat": ["throat@5.0.0", "", {}, "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="], + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], - "token-types": ["token-types@6.0.3", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-IKJ6EzuPPWtKtEIEPpIdXv9j5j2LGJEYk0CKY2efgKoYKLBiZdh6iQkLVBow/CB3phyWAWCyk+bZeaimJn6uRQ=="], + "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="], "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], "ts-typed-json": ["ts-typed-json@0.3.2", "", {}, "sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA=="], - "tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + "tweetnacl": ["tweetnacl@1.0.3", "", {}, "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="], + + "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], + "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], "typical": ["typical@4.0.0", "", {}, "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="], "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], - "uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="], + "uint8array-extras": ["uint8array-extras@1.4.1", "", {}, "sha512-+NWHrac9dvilNgme+gP4YrBSumsaMZP0fNBtXXFIf33RLLKEcBUKaQZ7ULUbS0sBfcjxIZ4V96OTRkCbM7hxpw=="], - "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + + "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], + + "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], + + "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.0", "", {}, "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg=="], + + "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.1.0", "", {}, "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w=="], "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], + "utf8": ["utf8@3.0.0", "", {}, "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "util-extend": ["util-extend@1.0.3", "", {}, "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA=="], + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], "valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="], @@ -472,6 +1249,12 @@ "validate-npm-package-name": ["validate-npm-package-name@3.0.0", "", { "dependencies": { "builtins": "^1.0.3" } }, "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw=="], + "vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="], + + "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], + + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], @@ -484,6 +1267,10 @@ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "write-file-atomic": ["write-file-atomic@4.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" } }, "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg=="], + + "ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -492,13 +1279,35 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + + "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "cmake-js/axios": ["axios@1.10.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw=="], + "chrome-launcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "cmake-js/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], + "chromium-edge-launcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "cmake-js/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], + + "cmake-js/fs-extra": ["fs-extra@11.3.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g=="], "cmake-js/npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], @@ -510,14 +1319,44 @@ "command-line-usage/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], + "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "elliptic/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "gauge/string-width": ["string-width@1.0.2", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw=="], "gauge/strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="], + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "import-fresh/resolve-from": ["resolve-from@3.0.0", "", {}, "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="], + + "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "jest-util/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + + "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "memory-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "metro/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "metro-source-map/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "metro-symbolicate/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "node-abi/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], @@ -528,8 +1367,32 @@ "prebuildify/node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], + + "rxjs/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "send/on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + + "stacktrace-parser/type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], + "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "table-layout/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], @@ -542,9 +1405,7 @@ "wordwrapjs/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], - "bl/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - - "cmake-js/fs-extra/jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], + "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "cmake-js/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -556,13 +1417,17 @@ "command-line-usage/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + "connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "gauge/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@1.0.0", "", { "dependencies": { "number-is-nan": "^1.0.0" } }, "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw=="], "gauge/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], - "memory-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "tar-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "cmake-js/npmlog/are-we-there-yet/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], @@ -570,8 +1435,6 @@ "command-line-usage/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], - "cmake-js/npmlog/are-we-there-yet/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "command-line-usage/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], } } diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 08804bc0f..5bb4f4f08 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -1,6 +1,11 @@ { "name": "dlt-connector", + "repository": "git@github.com:gradido/gradido.git", + "description": "Gradido DLT-Connector", + "author": "Gradido Academy - https://www.gradido.net", + "license": "Apache-2.0", "version": "1.0.50", + "private": true, "scripts": { "start": "bun run src/index.ts", "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --external=@iota/client", @@ -19,10 +24,13 @@ "@biomejs/biome": "2.0.0", "@elysiajs/trpc": "^1.1.0", "@elysiajs/websocket": "^0.2.8", + "@hashgraph/sdk": "^2.70.0", + "@sinclair/typebox": "^0.34.33", + "@sinclair/typemap": "^0.10.1", "@trpc/server": "^11.4.3", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", - "elysia": "^1.3.5", + "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", diff --git a/dlt-connector/src/KeyPairCacheManager.ts b/dlt-connector/src/KeyPairCacheManager.ts index b5501132c..a74780471 100644 --- a/dlt-connector/src/KeyPairCacheManager.ts +++ b/dlt-connector/src/KeyPairCacheManager.ts @@ -1,8 +1,8 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { KeyPairIdentifier } from './data/KeyPairIdentifier.logic' import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from './config/const' +import { HieroId } from './schemas/typeGuard.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -13,7 +13,7 @@ import { LOG4JS_BASE_CATEGORY } from './config/const' export class KeyPairCacheManager { private static instance: KeyPairCacheManager private cache: Map = new Map() - private homeCommunityUUID: string | undefined + private homeCommunityTopicId: HieroId | undefined private logger: Logger /** @@ -37,15 +37,15 @@ export class KeyPairCacheManager { return KeyPairCacheManager.instance } - public setHomeCommunityUUID(uuid: string): void { - this.homeCommunityUUID = uuid + public setHomeCommunityTopicId(topicId: HieroId): void { + this.homeCommunityTopicId = topicId } - public getHomeCommunityUUID(): string { - if (!this.homeCommunityUUID) { - throw new Error('home community uuid is not set') + public getHomeCommunityTopicId(): HieroId { + if (!this.homeCommunityTopicId) { + throw new Error('home community topic id is not set') } - return this.homeCommunityUUID + return this.homeCommunityTopicId } public findKeyPair(input: string): KeyPairEd25519 | undefined { @@ -63,7 +63,10 @@ export class KeyPairCacheManager { this.cache.set(input, keyPair) } - public async getKeyPair(input: string, createKeyPair: () => Promise): Promise { + public async getKeyPair( + input: string, + createKeyPair: () => Promise, + ): Promise { const keyPair = this.cache.get(input) if (!keyPair) { const keyPair = await createKeyPair() diff --git a/dlt-connector/src/client/GradidoNode/api.ts b/dlt-connector/src/client/GradidoNode/api.ts index fa8672a23..383f1c3f4 100644 --- a/dlt-connector/src/client/GradidoNode/api.ts +++ b/dlt-connector/src/client/GradidoNode/api.ts @@ -1,18 +1,18 @@ import { AddressType, ConfirmedTransaction } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' import * as v from 'valibot' -import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' -import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' -import { rpcCall, rpcCallResolved, GradidoNodeRequestError } from './jsonrpc' -import { - TransactionsRangeInput, - TransactionIdentifierInput, - transactionsRangeSchema, - transactionIdentifierSchema -} from './input.schema' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Uuidv4Hash } from '../../data/Uuidv4Hash' -import { Hex32, Hex32Input, hex32Schema } from '../../schemas/typeGuard.schema' +import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' +import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' +import { Hex32, Hex32Input, HieroId, hex32Schema } from '../../schemas/typeGuard.schema' +import { + TransactionIdentifierInput, + TransactionsRangeInput, + transactionIdentifierSchema, + transactionsRangeSchema, +} from './input.schema' +import { GradidoNodeRequestError, rpcCall, rpcCallResolved } from './jsonrpc' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) @@ -21,7 +21,7 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) * get list of confirmed transactions from a specific community * @param input fromTransactionId is the id of the first transaction to return * @param input maxResultCount is the max number of transactions to return - * @param input topic is the community topic + * @param input topic is the community hiero topic id * @returns list of confirmed transactions * @throws GradidoNodeRequestError * @example @@ -35,7 +35,7 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) */ async function getTransactions(input: TransactionsRangeInput): Promise { const parameter = { ...v.parse(transactionsRangeSchema, input), format: 'base64' } - const result = await rpcCallResolved<{transactions: string[]}>('getTransactions', parameter) + const result = await rpcCallResolved<{ transactions: string[] }>('getTransactions', parameter) return result.transactions.map((transactionBase64) => v.parse(confirmedTransactionSchema, transactionBase64), ) @@ -44,12 +44,13 @@ async function getTransactions(input: TransactionsRangeInput): Promise { +async function getTransaction( + transactionIdentifier: TransactionIdentifierInput, +): Promise { const parameter = { ...v.parse(transactionIdentifierSchema, transactionIdentifier), format: 'base64', @@ -74,7 +75,9 @@ async function getTransaction(transactionIdentifier: TransactionIdentifierInput) * @throws GradidoNodeRequestError */ -async function getLastTransaction(iotaTopic: Uuidv4Hash): Promise { +async function getLastTransaction( + iotaTopic: Uuidv4Hash, +): Promise { const response = await rpcCall<{ transaction: string }>('getlasttransaction', { format: 'base64', topic: iotaTopic.getAsHexString(), @@ -92,19 +95,19 @@ async function getLastTransaction(iotaTopic: Uuidv4Hash): Promise { +async function getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise { const parameter = { pubkey: v.parse(hex32Schema, pubkey), - communityId: iotaTopic.getAsHexString(), + communityId: hieroTopic, } const response = await rpcCallResolved<{ addressType: string }>('getaddresstype', parameter) return v.parse(addressTypeSchema, response.addressType) @@ -118,17 +121,26 @@ async function getAddressType(pubkey: Hex32Input, iotaTopic: Uuidv4Hash): Promis * @returns the public key of the user as hex32 string or undefined if user is not found * @throws GradidoNodeRequestError */ -async function findUserByNameHash(nameHash: Uuidv4Hash, iotaTopic: Uuidv4Hash): Promise { +async function findUserByNameHash( + nameHash: Uuidv4Hash, + hieroTopic: HieroId, +): Promise { const parameter = { nameHash: nameHash.getAsHexString(), - communityId: iotaTopic.getAsHexString(), + communityId: hieroTopic, } - const response = await rpcCall<{ pubkey: string; timeUsed: string }>('findUserByNameHash', parameter) - if(response.isSuccess()) { + const response = await rpcCall<{ pubkey: string; timeUsed: string }>( + 'findUserByNameHash', + parameter, + ) + if (response.isSuccess()) { logger.info(`call findUserByNameHash, used ${response.result.timeUsed}`) return v.parse(hex32Schema, response.result.pubkey) } - if (response.isError() && response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND) { + if ( + response.isError() && + response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND + ) { logger.debug(`call findUserByNameHash, return with error: ${response.error.message}`) } return undefined @@ -136,10 +148,10 @@ async function findUserByNameHash(nameHash: Uuidv4Hash, iotaTopic: Uuidv4Hash): /** * getTransactionsForAccount - * get list of confirmed transactions for a specific account + * get list of confirmed transactions for a specific account * @param transactionRange the range of transactions to return * @param pubkey the public key of the account - * @returns list of confirmed transactions + * @returns list of confirmed transactions * @throws GradidoNodeRequestError */ async function getTransactionsForAccount( @@ -151,7 +163,10 @@ async function getTransactionsForAccount( pubkey: v.parse(hex32Schema, pubkey), format: 'base64', } - const response = await rpcCallResolved<{transactions: string[]}>('listtransactionsforaddress', parameter) + const response = await rpcCallResolved<{ transactions: string[] }>( + 'listtransactionsforaddress', + parameter, + ) return response.transactions.map((transactionBase64) => v.parse(confirmedTransactionSchema, transactionBase64), ) diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts index b207f935a..218805c3f 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -1,36 +1,35 @@ import * as v from 'valibot' -import { hex32Schema, iotaMessageIdSchema } from '../../schemas/typeGuard.schema' +import { hieroIdSchema, hieroTransactionIdSchema } from '../../schemas/typeGuard.schema' export const transactionsRangeSchema = v.object({ // default value is 1, from first transactions - fromTransactionId: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1), + fromTransactionId: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1), // default value is 100, max 100 transactions - maxResultCount: v.undefinedable(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100), - topic: hex32Schema, + maxResultCount: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100), + topic: hieroIdSchema, }) export type TransactionsRangeInput = v.InferInput - // allow TransactionIdentifier to only contain either transactionNr or iotaMessageId export const transactionIdentifierSchema = v.pipe( v.object({ transactionNr: v.nullish( v.pipe(v.number('expect number type'), v.minValue(1, 'expect number >= 1')), - undefined + undefined, ), - iotaMessageId: v.nullish(iotaMessageIdSchema, undefined), - topic: hex32Schema, + hieroTransactionId: v.nullish(hieroTransactionIdSchema, undefined), + topic: hieroIdSchema, }), v.custom((value: any) => { - const setFieldsCount = Number(value.transactionNr !== undefined) + Number(value.iotaMessageId !== undefined) + const setFieldsCount = + Number(value.transactionNr !== undefined) + Number(value.hieroTransactionId !== undefined) if (setFieldsCount !== 1) { return false } return true - }, 'expect transactionNr or iotaMessageId not both') + }, 'expect transactionNr or hieroTransactionId not both'), ) export type TransactionIdentifierInput = v.InferInput export type TransactionIdentifier = v.InferOutput - diff --git a/dlt-connector/src/client/GradidoNode/jsonrpc.ts b/dlt-connector/src/client/GradidoNode/jsonrpc.ts index 6cd053d87..b93ff65f0 100644 --- a/dlt-connector/src/client/GradidoNode/jsonrpc.ts +++ b/dlt-connector/src/client/GradidoNode/jsonrpc.ts @@ -1,9 +1,9 @@ -import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' -import { isPortOpenRetry } from '../../utils/network' -import { CONFIG } from '../../config' import JsonRpcClient from 'jsonrpc-ts-client' +import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' +import { getLogger } from 'log4js' +import { CONFIG } from '../../config' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { isPortOpenRetry } from '../../utils/network' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) @@ -24,7 +24,10 @@ export class GradidoNodeRequestError extends Error { } // return result on success or throw error -export function resolveResponse(response: JsonRpcEitherResponse, onSuccess: (result: T) => R): R { +export function resolveResponse( + response: JsonRpcEitherResponse, + onSuccess: (result: T) => R, +): R { if (response.isSuccess()) { return onSuccess(response.result) } else if (response.isError()) { @@ -36,7 +39,10 @@ export function resolveResponse(response: JsonRpcEitherResponse, onSucc type WithTimeUsed = T & { timeUsed?: string } // template rpcCall, check first if port is open before executing json rpc 2.0 request -export async function rpcCall(method: string, parameter: any): Promise> { +export async function rpcCall( + method: string, + parameter: any, +): Promise> { logger.debug('call %s with %s', method, parameter) await isPortOpenRetry(CONFIG.NODE_SERVER_URL) return client.exec(method, parameter) @@ -51,4 +57,4 @@ export async function rpcCallResolved(method: string, parameter: any): Promis } return result as T }) -} \ No newline at end of file +} diff --git a/dlt-connector/src/client/HieroClient.ts b/dlt-connector/src/client/HieroClient.ts new file mode 100644 index 000000000..d7be17eb3 --- /dev/null +++ b/dlt-connector/src/client/HieroClient.ts @@ -0,0 +1,74 @@ +import { + AccountBalance, + AccountBalanceQuery, + Client, + LocalProvider, + PrivateKey, + TopicMessageSubmitTransaction, + TransactionReceipt, + TransactionResponse, + Wallet, +} from '@hashgraph/sdk' +import { GradidoTransaction } from 'gradido-blockchain-js' +import { getLogger, Logger } from 'log4js' +import { CONFIG } from '../config' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { HieroId } from '../schemas/typeGuard.schema' + +export class HieroClient { + private static instance: HieroClient + wallet: Wallet + logger: Logger + + private constructor() { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) + const provider = LocalProvider.fromClient(Client.forName(CONFIG.HIERO_HEDERA_NETWORK)) + let operatorKey: PrivateKey + if (CONFIG.HIERO_OPERATOR_KEY.length === 64) { + operatorKey = PrivateKey.fromStringED25519(CONFIG.HIERO_OPERATOR_KEY) + } else { + operatorKey = PrivateKey.fromStringECDSA(CONFIG.HIERO_OPERATOR_KEY) + } + this.wallet = new Wallet(CONFIG.HIERO_OPERATOR_ID, operatorKey, provider) + } + + public static getInstance(): HieroClient { + if (!CONFIG.HIERO_ACTIVE) { + throw new Error('hiero is disabled via config...') + } + if (!HieroClient.instance) { + HieroClient.instance = new HieroClient() + } + + return HieroClient.instance + } + + public async sendMessage( + topicId: HieroId, + transaction: GradidoTransaction, + ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { + const serializedTransaction = transaction.getSerializedTransaction() + if (!serializedTransaction) { + throw new Error('cannot serialize transaction') + } + // send one message + const hieroTransaction = await new TopicMessageSubmitTransaction({ + topicId, + message: serializedTransaction.data(), + }).freezeWithSigner(this.wallet) + const signedHieroTransaction = await hieroTransaction.signWithSigner(this.wallet) + const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) + const sendReceipt = await sendResponse.getReceiptWithSigner(this.wallet) + this.logger.info( + `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, + ) + return { receipt: sendReceipt, response: sendResponse } + } + + public async getBalance(): Promise { + const balance = await new AccountBalanceQuery() + .setAccountId(this.wallet.getAccountId()) + .executeWithSigner(this.wallet) + return balance + } +} diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 50904d198..7e98f82f9 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -1,21 +1,10 @@ -import { gql, GraphQLClient } from 'graphql-request' +import { GraphQLClient, gql } from 'graphql-request' import { SignJWT } from 'jose' - -import { CONFIG } from '../../config' -import { communitySchema, type Community } from './community.schema' import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' import * as v from 'valibot' - -const homeCommunity = gql` - query { - homeCommunity { - uuid - foreign - creationDate - } - } -` +import { CONFIG } from '../../config' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { type Community, communitySchema, homeCommunityGraphqlQuery } from './community.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -26,7 +15,7 @@ const homeCommunity = gql` export class BackendClient { private static instance: BackendClient client: GraphQLClient - logger: Logger + logger: Logger /** * The Singleton's constructor should always be private to prevent direct @@ -56,14 +45,14 @@ export class BackendClient { public static getInstance(): BackendClient | undefined { if (!BackendClient.instance) { BackendClient.instance = new BackendClient() - } + } return BackendClient.instance } public async getHomeCommunityDraft(): Promise { this.logger.info('check home community on backend') const { data, errors } = await this.client.rawRequest<{ homeCommunity: Community }>( - homeCommunity, + homeCommunityGraphqlQuery, {}, // empty variables await this.getRequestHeader(), ) diff --git a/dlt-connector/src/client/backend/community.schema.test.ts b/dlt-connector/src/client/backend/community.schema.test.ts index 42cf9dc7e..4d2931ed0 100644 --- a/dlt-connector/src/client/backend/community.schema.test.ts +++ b/dlt-connector/src/client/backend/community.schema.test.ts @@ -1,21 +1,21 @@ -import { communitySchema } from './community.schema' -import { uuidv4Schema } from '../../schemas/typeGuard.schema' -import * as v from 'valibot' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' +import * as v from 'valibot' +import { uuidv4Schema } from '../../schemas/typeGuard.schema' +import { communitySchema } from './community.schema' describe('community.schema', () => { it('community', () => { - expect(v.parse(communitySchema, { - uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', - foreign: false, - createdAt: '2021-01-01', - })).toEqual( - { - uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), + expect( + v.parse(communitySchema, { + uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', foreign: false, - createdAt: new Date('2021-01-01'), - }, - ) + createdAt: '2021-01-01', + }), + ).toEqual({ + uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), + foreign: false, + createdAt: new Date('2021-01-01'), + }) }) }) diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts index af8cf01bd..182a41368 100644 --- a/dlt-connector/src/client/backend/community.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -1,6 +1,7 @@ +import { gql } from 'graphql-request' import * as v from 'valibot' -import { uuidv4Schema } from '../../schemas/typeGuard.schema' import { dateSchema } from '../../schemas/typeConverter.schema' +import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' /** * Schema Definitions for rpc call parameter, when dlt-connector is called from backend @@ -11,9 +12,22 @@ import { dateSchema } from '../../schemas/typeConverter.schema' */ export const communitySchema = v.object({ uuid: uuidv4Schema, + topicId: hieroIdSchema, foreign: v.boolean('expect boolean type'), createdAt: dateSchema, }) export type CommunityInput = v.InferInput export type Community = v.InferOutput + +// graphql query for getting home community in tune with community schema +export const homeCommunityGraphqlQuery = gql` + query { + homeCommunity { + uuid + topicId + foreign + creationDate + } + } +` diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 2d016eee2..9a9889cda 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -1,5 +1,6 @@ /* eslint-disable n/no-process-env */ import dotenv from 'dotenv' + dotenv.config() const logging = { @@ -25,7 +26,16 @@ const iota = { IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED ?? null, } -const apis = { +const hiero = { + HIERO_ACTIVE: process.env.HIERO_ACTIVE === 'true' || false, + HIERO_HEDERA_NETWORK: process.env.HIERO_HEDERA_NETWORK ?? 'testnet', + HIERO_OPERATOR_ID: process.env.HIERO_OPERATOR_ID ?? '0.0.2', + HIERO_OPERATOR_KEY: + process.env.HIERO_OPERATOR_KEY ?? + '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', +} + +const apis = { CONNECT_TIMEOUT_MS: process.env.CONNECT_TIMEOUT_MS ? Number.parseInt(process.env.CONNECT_TIMEOUT_MS) : 1000, @@ -45,5 +55,6 @@ export const CONFIG = { ...server, ...secrets, ...iota, + ...hiero, ...apis, } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts new file mode 100644 index 000000000..b9a170e43 --- /dev/null +++ b/dlt-connector/src/config/schema.ts @@ -0,0 +1,24 @@ +import * as v from 'valibot' + +export const HIERO_ACTIVE = v.nullish( + v.boolean('Flag to indicate if the Hiero (Hedera Hashgraph Ledger) service is used.'), + false, +) + +export const HIERO_HEDERA_NETWORK = v.nullish( + v.union([v.literal('mainnet'), v.literal('testnet'), v.literal('previewnet')]), + 'testnet', +) + +export const HIERO_OPERATOR_ID = v.nullish( + v.pipe(v.string('The operator ID for Hiero integration'), v.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/)), + '0.0.2', +) + +export const HIERO_OPERATOR_KEY = v.nullish( + v.pipe( + v.string('The operator key for Hiero integration, default is for local default node'), + v.regex(/^[0-9a-fA-F]{64,96}$/), + ), + '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', +) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index b0bade47b..437d9a458 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -1,14 +1,10 @@ import { MemoryBlock } from 'gradido-blockchain-js' -import { IdentifierAccount, IdentifierAccountInput, identifierAccountSchema } from '../schemas/account.schema' import { ParameterError } from '../errors' -import * as v from 'valibot' +import { IdentifierAccount } from '../schemas/account.schema' +import { HieroId } from '../schemas/typeGuard.schema' export class KeyPairIdentifierLogic { - public identifier: IdentifierAccount - public constructor(identifier: IdentifierAccountInput) { - // check if data structure is like expected and fill in defaults - this.identifier = v.parse(identifierAccountSchema, identifier) - } + public constructor(public identifier: IdentifierAccount) {} isCommunityKeyPair(): boolean { return !this.identifier.seed && !this.identifier.account @@ -36,19 +32,21 @@ export class KeyPairIdentifierLogic { getSeed(): string { if (!this.identifier.seed) { - throw new Error('get seed called on non seed key pair identifier, please check first with isSeedKeyPair()') + throw new Error( + 'get seed called on non seed key pair identifier, please check first with isSeedKeyPair()', + ) } return this.identifier.seed.seed } - getCommunityUuid(): string { - return this.identifier.communityUuid + getCommunityTopicId(): HieroId { + return this.identifier.communityTopicId } getUserUuid(): string { if (!this.identifier.account) { throw new Error( - 'get user uuid called on non user key pair identifier, please check first with isUserKeyPair() or isAccountKeyPair()' + 'get user uuid called on non user key pair identifier, please check first with isUserKeyPair() or isAccountKeyPair()', ) } return this.identifier.account.userUuid @@ -57,19 +55,23 @@ export class KeyPairIdentifierLogic { getAccountNr(): number { if (!this.identifier.account?.accountNr) { throw new Error( - 'get account nr called on non account key pair identifier, please check first with isAccountKeyPair()' + 'get account nr called on non account key pair identifier, please check first with isAccountKeyPair()', ) } return this.identifier.account.accountNr } - getSeedKey(): string { return this.getSeed() } - getCommunityKey(): string { return this.getCommunityUuid() } - getCommunityUserKey(): string { + getSeedKey(): string { + return this.getSeed() + } + getCommunityKey(): HieroId { + return this.getCommunityTopicId() + } + getCommunityUserKey(): string { return this.createCommunityUserHash() } - getCommunityUserAccountKey(): string { - return this.createCommunityUserHash() + this.getAccountNr().toString() + getCommunityUserAccountKey(): string { + return this.createCommunityUserHash() + this.getAccountNr().toString() } getKey(): string { @@ -86,12 +88,11 @@ export class KeyPairIdentifierLogic { } private createCommunityUserHash(): string { - if (!this.identifier.account?.userUuid || !this.identifier.communityUuid) { - throw new ParameterError('userUuid and/or communityUuid is undefined') + if (!this.identifier.account?.userUuid || !this.identifier.communityTopicId) { + throw new ParameterError('userUuid and/or communityTopicId is undefined') } - const resultHexString = - this.identifier.communityUuid.replace(/-/g, '') - + this.identifier.account.userUuid.replace(/-/g, '') + const resultHexString = + this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') return MemoryBlock.fromHex(resultHexString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/data/Uuidv4Hash.ts b/dlt-connector/src/data/Uuidv4Hash.ts index 541f412d2..338dd4d4d 100644 --- a/dlt-connector/src/data/Uuidv4Hash.ts +++ b/dlt-connector/src/data/Uuidv4Hash.ts @@ -1,13 +1,19 @@ import { MemoryBlock } from 'gradido-blockchain-js' -import { Uuidv4, Hex32, hex32Schema, MemoryBlock32, memoryBlock32Schema } from '../schemas/typeGuard.schema' import * as v from 'valibot' +import { + Hex32, + hex32Schema, + MemoryBlock32, + memoryBlock32Schema, + Uuidv4, +} from '../schemas/typeGuard.schema' /** * Uuidv4Hash is a class that represents a uuidv4 BLAKE2b hash * to get the hash, the - in the uuidv4 will be removed and the result interpreted as hex string - * then the hash will be calculated with BLAKE2b algorithm + * then the hash will be calculated with BLAKE2b algorithm * crypto_generichash from libsodium will be called when calling MemoryBlock.calculateHash() - * + * * This will be used as NameHash for user identification (user uuid as input) * This will be used as IotaTopic for transactions (community uuid as input) */ @@ -17,7 +23,10 @@ export class Uuidv4Hash { uuidv4HashString: Hex32 | undefined constructor(uuidv4: Uuidv4) { - this.uuidv4Hash = v.parse(memoryBlock32Schema, MemoryBlock.fromHex(uuidv4.replace(/-/g, '')).calculateHash()) + this.uuidv4Hash = v.parse( + memoryBlock32Schema, + MemoryBlock.fromHex(uuidv4.replace(/-/g, '')).calculateHash(), + ) } getAsMemoryBlock(): MemoryBlock32 { diff --git a/dlt-connector/src/enum/AddressType.ts b/dlt-connector/src/enum/AddressType.ts index 8ac2f05fc..a19abbf78 100644 --- a/dlt-connector/src/enum/AddressType.ts +++ b/dlt-connector/src/enum/AddressType.ts @@ -4,9 +4,9 @@ import { AddressType_COMMUNITY_HUMAN, AddressType_COMMUNITY_PROJECT, AddressType_CRYPTO_ACCOUNT, + AddressType_DEFERRED_TRANSFER, AddressType_NONE, AddressType_SUBACCOUNT, - AddressType_DEFERRED_TRANSFER, } from 'gradido-blockchain-js' export enum AddressType { @@ -18,4 +18,4 @@ export enum AddressType { NONE = AddressType_NONE, SUBACCOUNT = AddressType_SUBACCOUNT, DEFERRED_TRANSFER = AddressType_DEFERRED_TRANSFER, -} \ No newline at end of file +} diff --git a/dlt-connector/src/enum/GradidoNodeErrorCodes.ts b/dlt-connector/src/enum/GradidoNodeErrorCodes.ts index 49153dc15..afbf9dd4d 100644 --- a/dlt-connector/src/enum/GradidoNodeErrorCodes.ts +++ b/dlt-connector/src/enum/GradidoNodeErrorCodes.ts @@ -17,4 +17,4 @@ export enum GradidoNodeErrorCodes { // -32603 Internal error Internal JSON - RPC error. INTERNAL_ERROR = -32603, // -32000 to -32099 Server error Reserved for implementation-defined server-errors. -} \ No newline at end of file +} diff --git a/dlt-connector/src/enum/InputTransactionType.ts b/dlt-connector/src/enum/InputTransactionType.ts index 65c806afc..4aa4fc8cf 100755 --- a/dlt-connector/src/enum/InputTransactionType.ts +++ b/dlt-connector/src/enum/InputTransactionType.ts @@ -1,11 +1,11 @@ -// enum for graphql but with int because it is the same in backend -// for transaction type from backend -export enum InputTransactionType { - GRADIDO_TRANSFER = 'GRADIDO_TRANSFER', - GRADIDO_CREATION = 'GRADIDO_CREATION', - GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', - REGISTER_ADDRESS = 'REGISTER_ADDRESS', - GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', - GRADIDO_REDEEM_DEFERRED_TRANSFER = 'GRADIDO_REDEEM_DEFERRED_TRANSFER', - COMMUNITY_ROOT = 'COMMUNITY_ROOT', -} +// enum for graphql but with int because it is the same in backend +// for transaction type from backend +export enum InputTransactionType { + GRADIDO_TRANSFER = 'GRADIDO_TRANSFER', + GRADIDO_CREATION = 'GRADIDO_CREATION', + GROUP_FRIENDS_UPDATE = 'GROUP_FRIENDS_UPDATE', + REGISTER_ADDRESS = 'REGISTER_ADDRESS', + GRADIDO_DEFERRED_TRANSFER = 'GRADIDO_DEFERRED_TRANSFER', + GRADIDO_REDEEM_DEFERRED_TRANSFER = 'GRADIDO_REDEEM_DEFERRED_TRANSFER', + COMMUNITY_ROOT = 'COMMUNITY_ROOT', +} diff --git a/dlt-connector/src/errors.ts b/dlt-connector/src/errors.ts index 73e6fd0f4..c9be7c2a2 100644 --- a/dlt-connector/src/errors.ts +++ b/dlt-connector/src/errors.ts @@ -1,5 +1,5 @@ -import { TransactionIdentifier } from './schemas/transaction.schema' import { IdentifierAccount } from './schemas/account.schema' +import { TransactionIdentifier } from './schemas/transaction.schema' export class GradidoNodeError extends Error { constructor(message: string) { diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 7681719ed..68b7f4803 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,16 +1,16 @@ -import { Elysia } from 'elysia' -import { CONFIG } from './config' -import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' -import { getLogger, configure } from 'log4js' import { readFileSync } from 'node:fs' -import { isPortOpenRetry } from './utils/network' -import { BackendClient } from './client/backend/BackendClient' -import { KeyPairCacheManager } from './KeyPairCacheManager' -import { getTransaction } from './client/GradidoNode/api' -import { Uuidv4Hash } from './data/Uuidv4Hash' -import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' -import { keyGenerationSeedSchema } from './schemas/base.schema' +import { Elysia } from 'elysia' +import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' +import { configure, getLogger } from 'log4js' import * as v from 'valibot' +import { BackendClient } from './client/backend/BackendClient' +import { getTransaction } from './client/GradidoNode/api' +import { CONFIG } from './config' +import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' +import { KeyPairCacheManager } from './KeyPairCacheManager' +import { keyGenerationSeedSchema } from './schemas/base.schema' +import { isPortOpenRetry } from './utils/network' +import { appRoutes } from './server' async function main() { // configure log4js @@ -23,7 +23,7 @@ async function main() { logger.error('IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long') process.exit(1) } - + // load crypto keys for gradido blockchain lib loadCryptoKeys( MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), @@ -38,22 +38,21 @@ async function main() { // wait for backend server await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) const homeCommunity = await backend.getHomeCommunityDraft() - KeyPairCacheManager.getInstance().setHomeCommunityUUID(homeCommunity.uuid) - const topic = new Uuidv4Hash(homeCommunity.uuid).getAsHexString() - logger.info('home community topic: %s', topic) + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.topicId) + logger.info('home community topic: %s', homeCommunity.topicId) logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) // ask gradido node if community blockchain was created try { - if (!await getTransaction({ transactionNr: 1, topic })) { + if (!(await getTransaction({ transactionNr: 1, topic: homeCommunity.topicId }))) { // if not exist, create community root transaction await SendToIotaContext(homeCommunity) } } catch (e) { logger.error('error requesting gradido node: ', e) } - // listen for rpc request from backend (replace graphql with json rpc) - const app = new Elysia() - .get('/', () => "Hello Elysia") + // listen for rpc request from backend (graphql replaced with trpc and elysia) + new Elysia() + .use(appRoutes) .listen(CONFIG.DLT_CONNECTOR_PORT, () => { logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) }) diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts index 235deadac..30b824d86 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts @@ -1,11 +1,10 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { communityUuidToTopicSchema } from '../../client/backend/community.schema' -import * as v from 'valibot' +import { HieroId } from '../../schemas/typeGuard.schema' export abstract class AbstractRemoteKeyPairRole { - protected topic: string - public constructor(communityUuid: string) { - this.topic = v.parse(communityUuidToTopicSchema, communityUuid) + protected topic: HieroId + public constructor(communityTopicId: HieroId) { + this.topic = communityTopicId } public abstract retrieveKeyPair(): Promise } diff --git a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts index 517d33ae1..62ce06ecf 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts @@ -3,7 +3,10 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class AccountKeyPairRole extends AbstractKeyPairRole { - public constructor(private accountNr: number, private userKeyPair: KeyPairEd25519) { + public constructor( + private accountNr: number, + private userKeyPair: KeyPairEd25519, + ) { super() } diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts index 803b1d216..0d73d891d 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -1,19 +1,22 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' import { getTransaction } from '../../client/GradidoNode/api' - +import { + GradidoNodeInvalidTransactionError, + GradidoNodeMissingTransactionError, +} from '../../errors' +import { HieroId } from '../../schemas/typeGuard.schema' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' -import { GradidoNodeInvalidTransactionError, GradidoNodeMissingTransactionError } from '../../errors' export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { - public constructor(communityUuid: string) { - super(communityUuid) + public constructor(communityTopicId: HieroId) { + super(communityTopicId) } public async retrieveKeyPair(): Promise { const transactionIdentifier = { transactionNr: 1, - iotaTopic: this.topic, + topic: this.topic, } const firstTransaction = await getTransaction(transactionIdentifier) if (!firstTransaction) { @@ -22,21 +25,21 @@ export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { const transactionBody = firstTransaction.getGradidoTransaction()?.getTransactionBody() if (!transactionBody) { throw new GradidoNodeInvalidTransactionError( - 'Invalid transaction, body is missing', - transactionIdentifier + 'Invalid transaction, body is missing', + transactionIdentifier, ) } if (!transactionBody.isCommunityRoot()) { throw new GradidoNodeInvalidTransactionError( 'Invalid transaction, community root type expected', - transactionIdentifier + transactionIdentifier, ) } const communityRoot = transactionBody.getCommunityRoot() if (!communityRoot) { throw new GradidoNodeInvalidTransactionError( 'Invalid transaction, community root is missing', - transactionIdentifier + transactionIdentifier, ) } return new KeyPairEd25519(communityRoot.getPublicKey()) diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts index c6164119c..883b214e8 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts @@ -20,11 +20,10 @@ export async function KeyPairCalculation(input: KeyPairIdentifierLogic): Promise return new LinkedTransactionKeyPairRole(input.getSeed()).generateKeyPair() } // If input does not belong to the home community, handle as remote key pair - if (cache.getHomeCommunityUUID() !== input.getCommunityUuid()) { - const role = - input.isAccountKeyPair() - ? new RemoteAccountKeyPairRole(input.identifier) - : new ForeignCommunityKeyPairRole(input.getCommunityUuid()) + if (cache.getHomeCommunityTopicId() !== input.getCommunityTopicId()) { + const role = input.isAccountKeyPair() + ? new RemoteAccountKeyPairRole(input.identifier) + : new ForeignCommunityKeyPairRole(input.getCommunityTopicId()) return await role.retrieveKeyPair() } const communityKeyPair = await cache.getKeyPair(input.getCommunityKey(), async () => { @@ -37,10 +36,7 @@ export async function KeyPairCalculation(input: KeyPairIdentifierLogic): Promise return communityKeyPair } const userKeyPair = await cache.getKeyPair(input.getCommunityUserKey(), async () => { - return new UserKeyPairRole( - input.getUserUuid(), - communityKeyPair, - ).generateKeyPair() + return new UserKeyPairRole(input.getUserUuid(), communityKeyPair).generateKeyPair() }) if (!userKeyPair) { throw new Error("couldn't generate user key pair") diff --git a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts index d31fd9814..bb4aeedd8 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts @@ -1,7 +1,6 @@ import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' - -import { AbstractKeyPairRole } from './AbstractKeyPair.role' import { ParameterError } from '../../errors' +import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class LinkedTransactionKeyPairRole extends AbstractKeyPairRole { public constructor(private seed: string) { @@ -14,7 +13,9 @@ export class LinkedTransactionKeyPairRole extends AbstractKeyPairRole { const hash = new MemoryBlock(this.seed).calculateHash() const keyPair = KeyPairEd25519.create(hash) if (!keyPair) { - throw new ParameterError(`error creating Ed25519 KeyPair from seed: ${this.seed.substring(0, 5)}...`) + throw new ParameterError( + `error creating Ed25519 KeyPair from seed: ${this.seed.substring(0, 5)}...`, + ) } return keyPair } diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts index 4ae1af7d9..d1658d608 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -1,15 +1,14 @@ -import { KeyPairEd25519 } from 'gradido-blockchain-js' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' import { findUserByNameHash } from '../../client/GradidoNode/api' -import { IdentifierAccount } from '../../schemas/account.schema' +import { Uuidv4Hash } from '../../data/Uuidv4Hash' import { GradidoNodeMissingUserError, ParameterError } from '../../errors' +import { IdentifierAccount } from '../../schemas/account.schema' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' -import { uuid4ToHashSchema } from '../../schemas/typeConverter.schema' -import * as v from 'valibot' export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { public constructor(private identifier: IdentifierAccount) { - super(identifier.communityUuid) + super(identifier.communityTopicId) } public async retrieveKeyPair(): Promise { @@ -18,11 +17,11 @@ export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { } const accountPublicKey = await findUserByNameHash( - v.parse(uuid4ToHashSchema, this.identifier.account.userUuid), + new Uuidv4Hash(this.identifier.account.userUuid), this.topic, ) if (accountPublicKey) { - return new KeyPairEd25519(accountPublicKey) + return new KeyPairEd25519(MemoryBlock.createPtr(MemoryBlock.fromHex(accountPublicKey))) } throw new GradidoNodeMissingUserError('cannot find remote user', this.identifier) } diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts index 3762266b2..a2f57898c 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -4,7 +4,10 @@ import { hardenDerivationIndex } from '../../utils/derivationHelper' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class UserKeyPairRole extends AbstractKeyPairRole { - public constructor(private userUuid: string, private communityKeys: KeyPairEd25519) { + public constructor( + private userUuid: string, + private communityKeys: KeyPairEd25519, + ) { super() } diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts new file mode 100644 index 000000000..bf05b584c --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts @@ -0,0 +1,64 @@ +import { beforeAll, describe, expect, it } from 'bun:test' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { v4 as uuidv4 } from 'uuid' +import { UserKeyPairRole } from './UserKeyPair.role' + +let communityKeyPair: KeyPairEd25519 +describe('UserKeyPairRole', () => { + beforeAll(() => { + communityKeyPair = KeyPairEd25519.create(new MemoryBlock('test').calculateHash())! + }) + it('should generate key pair', () => { + const userUUidPublicKeyPairs = [ + { + userUuid: '648f28cc-209c-4696-b381-5156fc1a7bcb', + publicKeyHex: 'ebd636d7e1e7177c0990d2ce836d8ced8b05ad75d62a7120a5d4a67bdd9dddb9', + }, + { + userUuid: 'fb65ef70-4c33-4dbc-aca8-3bae2609b04b', + publicKeyHex: 'd89fe30c53852dc2c8281581e6904da396c3104fc11c0a6d9b4a0afa5ce54dc1', + }, + { + userUuid: 'd58b6355-a337-4c80-b593-18d78b5cdab0', + publicKeyHex: 'dafb51eb8143cc7b2559235978ab845922ca8efa938ece078f45957ae3b92458', + }, + { + userUuid: '61144289-f69b-43a7-8b7d-5dcf3fa8ca68', + publicKeyHex: '8d4db4ecfb65e40d1a4d4d4858be1ddd54b64aa845ceaa6698c336424ae0fc58', + }, + { + userUuid: 'c63e6870-196c-4013-b30a-d0a5170e8150', + publicKeyHex: 'c240a8978da03f24d75108c4f06550a9bde46c902684a6d19d8b990819f518c8', + }, + { + userUuid: '6b40a2c9-4c0f-426d-bb55-353967e89aa2', + publicKeyHex: '75531146e27b557085c09545e7a5e95f7bfd66d0de30c31befc34e4061f4e148', + }, + { + userUuid: '50c47820-6d15-449d-89c3-b1fd02674c80', + publicKeyHex: '2c9ccb9914009bb6f24e41659223a5f8ce200cb5a4abdd808db57819f43c0ea2', + }, + { + userUuid: 'dc902954-bfc1-412e-b2f6-857e8bd45f0f', + publicKeyHex: '4546870cf56093755c1f410a53c5908a5f30f26bc553110779e8bf5b841d904a', + }, + { + userUuid: 'd77cd665-0d60-4033-a887-07944466ccbe', + publicKeyHex: '6563a5ca2944ba47391afd11a46e65bb7eb90657179dbc2d6be88af9ffa849a9', + }, + { + userUuid: 'ee83ed52-8a37-4a8a-8eed-ffaaac7d0d03', + publicKeyHex: '03968833ee5d4839cb9091f39f76c9f5ca35f117b953229b59549cce907a60ea', + }, + ] + for (let i = 0; i < userUUidPublicKeyPairs.length; i++) { + const pair = userUUidPublicKeyPairs[i] + const userKeyPairRole = new UserKeyPairRole(pair.userUuid, communityKeyPair) + const accountKeyPair = userKeyPairRole.generateKeyPair() + expect(accountKeyPair).toBeDefined() + const publicKeyHex = accountKeyPair.getPublicKey()?.convertToHex() + expect(publicKeyHex).toHaveLength(64) + expect(publicKeyHex).toBe(pair.publicKeyHex) + } + }) +}) diff --git a/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts index ac9120e3d..df9ce2c59 100644 --- a/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts @@ -1,7 +1,8 @@ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' +import { HieroId } from '../../schemas/typeGuard.schema' export abstract class AbstractTransactionRole { abstract getGradidoTransactionBuilder(): Promise - abstract getSenderCommunityUuid(): string - abstract getRecipientCommunityUuid(): string + abstract getSenderCommunityTopicId(): HieroId + abstract getRecipientCommunityTopicId(): HieroId } diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts index 3beaa633d..c59939ccb 100644 --- a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts @@ -1,45 +1,41 @@ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' - +import { Community } from '../../client/backend/community.schema' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { HieroId } from '../../schemas/typeGuard.schema' import { AUF_ACCOUNT_DERIVATION_INDEX, GMW_ACCOUNT_DERIVATION_INDEX, hardenDerivationIndex, } from '../../utils/derivationHelper' - import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - import { AbstractTransactionRole } from './AbstractTransaction.role' -import { Community, CommunityInput, communitySchema } from '../../client/backend/community.schema' -import * as v from 'valibot' export class CommunityRootTransactionRole extends AbstractTransactionRole { - private com: Community - constructor(input: CommunityInput) { + constructor(private readonly community: Community) { super() - this.com = v.parse(communitySchema, input) } - getSenderCommunityUuid(): string { - return this.com.uuid + getSenderCommunityTopicId(): HieroId { + return this.community.topicId } - getRecipientCommunityUuid(): string { + getRecipientCommunityTopicId(): HieroId { throw new Error('cannot be used as cross group transaction') } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const communityKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ communityUuid: this.com.uuid })) + new KeyPairIdentifierLogic({ communityTopicId: this.community.topicId }), + ) const gmwKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), - ) + ) // as unknown as KeyPairEd25519 const aufKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), - ) + ) // as unknown as KeyPairEd25519 builder - .setCreatedAt(this.com.createdAt) + .setCreatedAt(this.community.createdAt) .setCommunityRoot( communityKeyPair.getPublicKey(), gmwKeyPair.getPublicKey(), diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index c930e1725..834f813c2 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -4,78 +4,69 @@ import { GradidoTransactionBuilder, TransferAmount, } from 'gradido-blockchain-js' - +import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { CreationTransactionInput, creationTransactionSchema, CreationTransaction } from '../../schemas/transaction.schema' import { KeyPairCacheManager } from '../../KeyPairCacheManager' -import { TRPCError } from '@trpc/server' - +import { + CreationTransaction, + creationTransactionSchema, + Transaction, +} from '../../schemas/transaction.schema' +import { HieroId } from '../../schemas/typeGuard.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' -import * as v from 'valibot' import { AbstractTransactionRole } from './AbstractTransaction.role' -import { Uuidv4, uuidv4Schema } from '../../schemas/typeConverter.schema' export class CreationTransactionRole extends AbstractTransactionRole { - private tx: CreationTransaction - private homeCommunityUuid: Uuidv4 - constructor(input: CreationTransactionInput) { + private readonly homeCommunityTopicId: HieroId + private readonly creationTransaction: CreationTransaction + constructor(transaction: Transaction) { super() - this.tx = v.parse(creationTransactionSchema, input) - this.homeCommunityUuid = v.parse( - uuidv4Schema, - KeyPairCacheManager.getInstance().getHomeCommunityUUID() - ) + this.creationTransaction = parse(creationTransactionSchema, transaction) + this.homeCommunityTopicId = KeyPairCacheManager.getInstance().getHomeCommunityTopicId() if ( - this.homeCommunityUuid !== this.tx.user.communityUuid || - this.homeCommunityUuid !== this.tx.linkedUser.communityUuid + this.homeCommunityTopicId !== this.creationTransaction.user.communityTopicId || + this.homeCommunityTopicId !== this.creationTransaction.linkedUser.communityTopicId ) { - throw new TRPCError({ - code: 'BAD_REQUEST', - message: 'creation: both recipient and signer must belong to home community', - }) + throw new Error('creation: both recipient and signer must belong to home community') } } - getSenderCommunityUuid(): string { - return this.tx.user.communityUuid + getSenderCommunityTopicId(): HieroId { + return this.creationTransaction.user.communityTopicId } - getRecipientCommunityUuid(): string { - throw new TRPCError({ - code: 'BAD_REQUEST', - message: 'creation: cannot be used as cross group transaction', - }) + getRecipientCommunityTopicId(): HieroId { + throw new Error('creation: cannot be used as cross group transaction') } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() // Recipient: user (account owner) const recipientKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(this.tx.user) + new KeyPairIdentifierLogic(this.creationTransaction.user), ) // Signer: linkedUser (admin/moderator) const signerKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(this.tx.linkedUser) + new KeyPairIdentifierLogic(this.creationTransaction.linkedUser), ) const homeCommunityKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ - communityUuid: this.homeCommunityUuid + new KeyPairIdentifierLogic({ + communityTopicId: this.homeCommunityTopicId, }), ) // Memo: encrypted, home community and recipient can decrypt it builder - .setCreatedAt(this.tx.createdAt) - .addMemo(new EncryptedMemo( - this.tx.memo, - new AuthenticatedEncryption(homeCommunityKeyPair), - new AuthenticatedEncryption(recipientKeyPair), - )) - .setTransactionCreation( - new TransferAmount( - recipientKeyPair.getPublicKey(), - this.tx.amount, + .setCreatedAt(this.creationTransaction.createdAt) + .addMemo( + new EncryptedMemo( + this.creationTransaction.memo, + new AuthenticatedEncryption(homeCommunityKeyPair), + new AuthenticatedEncryption(recipientKeyPair), ), - this.tx.targetDate, + ) + .setTransactionCreation( + new TransferAmount(recipientKeyPair.getPublicKey(), this.creationTransaction.amount), + this.creationTransaction.targetDate, ) .sign(signerKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts index 655542537..36569d708 100644 --- a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts @@ -5,53 +5,52 @@ import { GradidoTransfer, TransferAmount, } from 'gradido-blockchain-js' - +import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { IdentifierSeed, identifierSeedSchema } from '../../schemas/account.schema' +import { + DeferredTransferTransaction, + deferredTransferTransactionSchema, + Transaction, +} from '../../schemas/transaction.schema' +import { HieroId } from '../../schemas/typeGuard.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - import { AbstractTransactionRole } from './AbstractTransaction.role' -import { DeferredTransferTransactionInput, deferredTransferTransactionSchema, DeferredTransferTransaction } from '../../schemas/transaction.schema' -import * as v from 'valibot' -import { TRPCError } from '@trpc/server' -import { identifierSeedSchema, IdentifierSeed } from '../../schemas/account.schema' export class DeferredTransferTransactionRole extends AbstractTransactionRole { - private tx: DeferredTransferTransaction - private seed: IdentifierSeed - constructor(protected input: DeferredTransferTransactionInput) { + private readonly seed: IdentifierSeed + private readonly deferredTransferTransaction: DeferredTransferTransaction + constructor(transaction: Transaction) { super() - this.tx = v.parse(deferredTransferTransactionSchema, input) - this.seed = v.parse(identifierSeedSchema, input.linkedUser.seed) + this.deferredTransferTransaction = parse(deferredTransferTransactionSchema, transaction) + this.seed = parse(identifierSeedSchema, this.deferredTransferTransaction.linkedUser.seed) } - getSenderCommunityUuid(): string { - return this.tx.user.communityUuid + getSenderCommunityTopicId(): HieroId { + return this.deferredTransferTransaction.user.communityTopicId } - getRecipientCommunityUuid(): string { - throw new TRPCError({ - code: 'NOT_IMPLEMENTED', - message: 'deferred transfer: cannot be used as cross group transaction yet', - }) + getRecipientCommunityTopicId(): HieroId { + throw new Error('deferred transfer: cannot be used as cross group transaction yet') } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const senderKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(this.tx.user) + new KeyPairIdentifierLogic(this.deferredTransferTransaction.user), ) const recipientKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ - communityUuid: this.tx.linkedUser.communityUuid, + new KeyPairIdentifierLogic({ + communityTopicId: this.deferredTransferTransaction.linkedUser.communityTopicId, seed: this.seed, - }) + }), ) builder - .setCreatedAt(this.tx.createdAt) + .setCreatedAt(this.deferredTransferTransaction.createdAt) .addMemo( new EncryptedMemo( - this.tx.memo, + this.deferredTransferTransaction.memo, new AuthenticatedEncryption(senderKeyPair), new AuthenticatedEncryption(recipientKeyPair), ), @@ -60,13 +59,13 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), - this.tx.amount.calculateCompoundInterest( - this.tx.timeoutDuration.getSeconds(), + this.deferredTransferTransaction.amount.calculateCompoundInterest( + this.deferredTransferTransaction.timeoutDuration.getSeconds(), ), ), recipientKeyPair.getPublicKey(), ), - this.tx.timeoutDuration, + this.deferredTransferTransaction.timeoutDuration, ) .sign(senderKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts index ae9115485..3d2574681 100644 --- a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts @@ -1,88 +1,71 @@ +import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { parse } from 'valibot' +import { getTransactionsForAccount } from '../../client/GradidoNode/api' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { - GradidoTransactionBuilder, - GradidoTransfer, - GradidoUnit, - TransferAmount, -} from 'gradido-blockchain-js' - -import { getTransactionsForAccount } from '@/client/GradidoNode' -import { KeyPairIdentifier } from '@/data/KeyPairIdentifier' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { UserIdentifier } from '@/graphql/input/UserIdentifier' -import { TransactionError } from '@/graphql/model/TransactionError' -import { communityUuidToTopic, uuid4ToHash } from '@/utils/typeConverter' - + RedeemDeferredTransferTransaction, + redeemDeferredTransferTransactionSchema, + Transaction, + UserAccount, +} from '../../schemas/transaction.schema' +import { HieroId } from '../../schemas/typeGuard.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - import { AbstractTransactionRole } from './AbstractTransaction.role' export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRole { - private linkedUser: UserIdentifier - constructor(protected self: TransactionDraft) { + private linkedUser: UserAccount + private readonly redeemDeferredTransferTransaction: RedeemDeferredTransferTransaction + constructor(transaction: Transaction) { super() - if (!this.self.linkedUser) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'transfer: linked user missing', - ) - } - this.linkedUser = this.self.linkedUser + this.redeemDeferredTransferTransaction = parse( + redeemDeferredTransferTransactionSchema, + transaction, + ) + this.linkedUser = this.redeemDeferredTransferTransaction.linkedUser } - getSenderCommunityUuid(): string { - return this.self.user.communityUuid + getSenderCommunityTopicId(): HieroId { + return this.redeemDeferredTransferTransaction.user.communityTopicId } - getRecipientCommunityUuid(): string { - return this.linkedUser.communityUuid + getRecipientCommunityTopicId(): HieroId { + return this.linkedUser.communityTopicId } public async getGradidoTransactionBuilder(): Promise { - if (!this.self.amount) { - throw new TransactionError( - TransactionErrorType.MISSING_PARAMETER, - 'redeem deferred transfer: amount missing', - ) - } const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.self.user)) + const senderKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.redeemDeferredTransferTransaction.user), + ) const senderPublicKey = senderKeyPair.getPublicKey() if (!senderPublicKey) { - throw new TransactionError( - TransactionErrorType.INVALID_PARAMETER, - "redeem deferred transfer: couldn't calculate sender public key", - ) + throw new Error("redeem deferred transfer: couldn't calculate sender public key") } // load deferred transfer transaction from gradido node const transactions = await getTransactionsForAccount( - senderPublicKey, - communityUuidToTopic(this.getSenderCommunityUuid()), + { maxResultCount: 2, topic: this.getSenderCommunityTopicId() }, + senderPublicKey.convertToHex(), ) if (!transactions || transactions.length !== 1) { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, - "redeem deferred transfer: couldn't find deferred transfer on Gradido Node", - ) + throw new Error("redeem deferred transfer: couldn't find deferred transfer on Gradido Node") } const deferredTransfer = transactions[0] const deferredTransferBody = deferredTransfer.getGradidoTransaction()?.getTransactionBody() if (!deferredTransferBody) { - throw new TransactionError( - TransactionErrorType.NOT_FOUND, + throw new Error( "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", ) } - const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifier(this.linkedUser)) + const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(this.linkedUser)) builder - .setCreatedAt(new Date(this.self.createdAt)) + .setCreatedAt(this.redeemDeferredTransferTransaction.createdAt) .setRedeemDeferredTransfer( deferredTransfer.getId(), new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), - GradidoUnit.fromString(this.self.amount), + this.redeemDeferredTransferTransaction.amount, ), recipientKeyPair.getPublicKey(), ), @@ -91,13 +74,11 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo for (let i = 0; i < memos.size(); i++) { builder.addMemo(memos.get(i)) } - const senderCommunity = this.self.user.communityUuid - const recipientCommunity = this.linkedUser.communityUuid + const senderCommunity = this.redeemDeferredTransferTransaction.user.communityTopicId + const recipientCommunity = this.linkedUser.communityTopicId if (senderCommunity !== recipientCommunity) { // we have a cross group transaction - builder - .setSenderCommunity(uuid4ToHash(senderCommunity).convertToHex()) - .setRecipientCommunity(uuid4ToHash(recipientCommunity).convertToHex()) + builder.setSenderCommunity(senderCommunity).setRecipientCommunity(recipientCommunity) } builder.sign(senderKeyPair) return builder diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts index a664a34c0..5eee0f164 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts @@ -1,69 +1,60 @@ -/* eslint-disable camelcase */ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' - +import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' - +import { Uuidv4Hash } from '../../data/Uuidv4Hash' +import { + IdentifierCommunityAccount, + identifierCommunityAccountSchema, +} from '../../schemas/account.schema' +import { + RegisterAddressTransaction, + registerAddressTransactionSchema, + Transaction, +} from '../../schemas/transaction.schema' +import { HieroId } from '../../schemas/typeGuard.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' - import { AbstractTransactionRole } from './AbstractTransaction.role' -import { RegisterAddressTransactionInput, registerAddressTransactionSchema, RegisterAddressTransaction } from '../../schemas/transaction.schema' -import { IdentifierAccount, IdentifierCommunityAccount, identifierCommunityAccountSchema } from '../../schemas/account.schema' -import * as v from 'valibot' -import { TRPCError } from '@trpc/server' -import { uuid4ToHashSchema } from '../../schemas/typeConverter.schema' export class RegisterAddressTransactionRole extends AbstractTransactionRole { - private tx: RegisterAddressTransaction - private account: IdentifierCommunityAccount - constructor(input: RegisterAddressTransactionInput) { + private readonly registerAddressTransaction: RegisterAddressTransaction + private readonly account: IdentifierCommunityAccount + constructor(input: Transaction) { super() - this.tx = v.parse(registerAddressTransactionSchema, input) - this.account = v.parse(identifierCommunityAccountSchema, input.user.account) + this.registerAddressTransaction = parse(registerAddressTransactionSchema, input) + this.account = parse(identifierCommunityAccountSchema, input.user.account) } - getSenderCommunityUuid(): string { - return this.tx.user.communityUuid + getSenderCommunityTopicId(): HieroId { + return this.registerAddressTransaction.user.communityTopicId } - getRecipientCommunityUuid(): string { - throw new TRPCError({ - code: 'NOT_IMPLEMENTED', - message: 'register address: cannot be used as cross group transaction yet', - }) + getRecipientCommunityTopicId(): HieroId { + throw new Error('register address: cannot be used as cross group transaction yet') } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const communityKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ communityUuid: this.tx.user.communityUuid }), - ) - const userKeyPairIdentifier: IdentifierAccount = { - communityUuid: this.tx.user.communityUuid, - account: { - userUuid: this.account.userUuid, - accountNr: 0, - }, - } - const accountKeyPairIdentifier: IdentifierAccount = { - communityUuid: this.tx.user.communityUuid, - account: { - userUuid: this.account.userUuid, - accountNr: this.account.accountNr, - }, - } - const userKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(userKeyPairIdentifier) + new KeyPairIdentifierLogic({ + communityTopicId: this.registerAddressTransaction.user.communityTopicId, + }), ) + const accountKeyPairIdentifier = this.registerAddressTransaction.user + // when accountNr is 0 it is the user account + const userKeyPairIdentifier = accountKeyPairIdentifier + userKeyPairIdentifier.account.accountNr = 0 + + const userKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(userKeyPairIdentifier)) const accountKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(accountKeyPairIdentifier) + new KeyPairIdentifierLogic(accountKeyPairIdentifier), ) builder - .setCreatedAt(this.tx.createdAt) + .setCreatedAt(this.registerAddressTransaction.createdAt) .setRegisterAddress( userKeyPair.getPublicKey(), - this.tx.accountType, - v.parse(uuid4ToHashSchema, this.account.userUuid), + this.registerAddressTransaction.accountType, + new Uuidv4Hash(this.account.userUuid).getAsMemoryBlock(), accountKeyPair.getPublicKey(), ) .sign(communityKeyPair) diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index 2607f6c8f..288ccfc77 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -1,24 +1,17 @@ /* eslint-disable camelcase */ import { GradidoTransaction, - InteractionSerialize, - InteractionValidate, - MemoryBlock, + InteractionValidate, + MemoryBlock, ValidateType_SINGLE, } from 'gradido-blockchain-js' - -import { sendMessage as iotaSendMessage } from '@/client/IotaClient' -import { InputTransactionType } from '@/graphql/enum/InputTransactionType' -import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType' -import { CommunityDraft } from '@/graphql/input/CommunityDraft' -import { TransactionDraft } from '@/graphql/input/TransactionDraft' -import { TransactionError } from '@/graphql/model/TransactionError' -import { TransactionRecipe } from '@/graphql/model/TransactionRecipe' -import { TransactionResult } from '@/graphql/model/TransactionResult' -import { logger } from '@/logging/logger' -import { LogError } from '@/server/LogError' -import { communityUuidToTopic } from '@/utils/typeConverter' - +import { getLogger } from 'log4js' +import { safeParse, parse } from 'valibot' +import { Community, communitySchema } from '../../client/backend/community.schema' +import { HieroClient } from '../../client/HieroClient' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { Transaction, transactionSchema } from '../../schemas/transaction.schema' +import { HieroId, HieroTransactionId, hieroTransactionIdSchema } from '../../schemas/typeGuard.schema' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' @@ -26,6 +19,9 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' +import { InputTransactionType } from '../../enum/InputTransactionType' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToIota.SendToIotaContext`) /** * @DCI-Context @@ -33,95 +29,74 @@ import { TransferTransactionRole } from './TransferTransaction.role' * send every transaction only once to iota! */ export async function SendToIotaContext( - input: TransactionDraft | CommunityDraft, -): Promise { + input: Transaction | Community, +): Promise { + // let gradido blockchain validator run, it will throw an exception when something is wrong const validate = (transaction: GradidoTransaction): void => { - try { - // throw an exception when something is wrong - const validator = new InteractionValidate(transaction) - validator.run(ValidateType_SINGLE) - } catch (e) { - if (e instanceof Error) { - throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e.message) - } else if (typeof e === 'string') { - throw new TransactionError(TransactionErrorType.VALIDATION_ERROR, e) - } else { - throw e - } - } + const validator = new InteractionValidate(transaction) + validator.run(ValidateType_SINGLE) } - const sendViaIota = async ( + // send transaction as hiero topic message + const sendViaHiero = async ( gradidoTransaction: GradidoTransaction, - topic: string, - ): Promise => { - // protobuf serializing function - const serialized = new InteractionSerialize(gradidoTransaction).run() - if (!serialized) { - throw new TransactionError( - TransactionErrorType.PROTO_ENCODE_ERROR, - 'cannot serialize transaction', - ) - } - const resultMessage = await iotaSendMessage( - Uint8Array.from(serialized.data()), - Uint8Array.from(Buffer.from(topic, 'hex')), - ) - logger.info('transmitted Gradido Transaction to Iota', { - messageId: resultMessage.messageId, - }) - return MemoryBlock.fromHex(resultMessage.messageId) + topic: HieroId, + ): Promise => { + const client = HieroClient.getInstance() + const resultMessage = await client.sendMessage(topic, gradidoTransaction) + const transactionId = resultMessage.response.transactionId.toString() + logger.info('transmitted Gradido Transaction to Iota', { transactionId }) + return transactionId } - let role: AbstractTransactionRole - if (input instanceof TransactionDraft) { - switch (input.type) { - case InputTransactionType.GRADIDO_CREATION: - role = new CreationTransactionRole(input) - break - case InputTransactionType.GRADIDO_TRANSFER: - role = new TransferTransactionRole(input) - break - case InputTransactionType.REGISTER_ADDRESS: - role = new RegisterAddressTransactionRole(input) - break - case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: - role = new DeferredTransferTransactionRole(input) - break - case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: - role = new RedeemDeferredTransferTransactionRole(input) - break - default: - throw new TransactionError( - TransactionErrorType.NOT_IMPLEMENTED_YET, - 'not supported transaction type: ' + input.type, - ) + // choose correct role based on transaction type and input type + const chooseCorrectRole = (input: Transaction | Community): AbstractTransactionRole => { + const transactionParsingResult = safeParse(transactionSchema, input) + const communityParsingResult = safeParse(communitySchema, input) + if (transactionParsingResult.success) { + const transaction = transactionParsingResult.output + switch (transaction.type) { + case InputTransactionType.GRADIDO_CREATION: + return new CreationTransactionRole(transaction) + case InputTransactionType.GRADIDO_TRANSFER: + return new TransferTransactionRole(transaction) + case InputTransactionType.REGISTER_ADDRESS: + return new RegisterAddressTransactionRole(transaction) + case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: + return new DeferredTransferTransactionRole(transaction) + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + return new RedeemDeferredTransferTransactionRole(transaction) + default: + throw new Error('not supported transaction type: ' + transaction.type) + } + } else if (communityParsingResult.success) { + return new CommunityRootTransactionRole(communityParsingResult.output) + } else { + throw new Error('not expected input') } - } else if (input instanceof CommunityDraft) { - role = new CommunityRootTransactionRole(input) - } else { - throw new LogError('not expected input') } + + const role = chooseCorrectRole(input) const builder = await role.getGradidoTransactionBuilder() if (builder.isCrossCommunityTransaction()) { const outboundTransaction = builder.buildOutbound() validate(outboundTransaction) - const outboundIotaMessageId = await sendViaIota( + const outboundIotaMessageId = await sendViaHiero( outboundTransaction, - communityUuidToTopic(role.getSenderCommunityUuid()), + role.getSenderCommunityTopicId(), ) - builder.setParentMessageId(outboundIotaMessageId) + builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundIotaMessageId))) const inboundTransaction = builder.buildInbound() validate(inboundTransaction) - await sendViaIota(inboundTransaction, communityUuidToTopic(role.getRecipientCommunityUuid())) - return new TransactionResult(new TransactionRecipe(outboundTransaction, outboundIotaMessageId)) + await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId()) + return parse(hieroTransactionIdSchema, outboundIotaMessageId) } else { const transaction = builder.build() validate(transaction) - const iotaMessageId = await sendViaIota( + const iotaMessageId = await sendViaHiero( transaction, - communityUuidToTopic(role.getSenderCommunityUuid()), + role.getSenderCommunityTopicId(), ) - return new TransactionResult(new TransactionRecipe(transaction, iotaMessageId)) + return parse(hieroTransactionIdSchema, iotaMessageId) } } diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index 344efeba5..f244bf472 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -4,60 +4,61 @@ import { GradidoTransactionBuilder, TransferAmount, } from 'gradido-blockchain-js' - +import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { + TransferTransaction, + transferTransactionSchema, + Transaction, +} from '../../schemas/transaction.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' -import { TransferTransactionInput, transferTransactionSchema, TransferTransaction } from '../../schemas/transaction.schema' -import * as v from 'valibot' -import { uuid4ToTopicSchema } from '../../schemas/typeConverter.schema' +import { HieroId } from '../../schemas/typeGuard.schema' export class TransferTransactionRole extends AbstractTransactionRole { - private tx: TransferTransaction - constructor(input: TransferTransactionInput) { + private transferTransaction: TransferTransaction + constructor(input: Transaction) { super() - this.tx = v.parse(transferTransactionSchema, input) + this.transferTransaction = parse(transferTransactionSchema, input) } - getSenderCommunityUuid(): string { - return this.tx.user.communityUuid + getSenderCommunityTopicId(): HieroId { + return this.transferTransaction.user.communityTopicId } - getRecipientCommunityUuid(): string { - return this.tx.linkedUser.communityUuid + getRecipientCommunityTopicId(): HieroId { + return this.transferTransaction.linkedUser.communityTopicId } public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() // sender + signer - const senderKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(this.tx.user) - ) + const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(this.transferTransaction.user)) // recipient const recipientKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(this.tx.linkedUser) + new KeyPairIdentifierLogic(this.transferTransaction.linkedUser), ) builder - .setCreatedAt(new Date(this.tx.createdAt)) + .setCreatedAt(this.transferTransaction.createdAt) .addMemo( new EncryptedMemo( - this.tx.memo, + this.transferTransaction.memo, new AuthenticatedEncryption(senderKeyPair), new AuthenticatedEncryption(recipientKeyPair), ), ) .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), this.tx.amount), + new TransferAmount(senderKeyPair.getPublicKey(), this.transferTransaction.amount), recipientKeyPair.getPublicKey(), ) - const senderCommunity = this.tx.user.communityUuid - const recipientCommunity = this.tx.linkedUser.communityUuid + const senderCommunity = this.transferTransaction.user.communityTopicId + const recipientCommunity = this.transferTransaction.linkedUser.communityTopicId if (senderCommunity !== recipientCommunity) { // we have a cross group transaction builder - .setSenderCommunity(v.parse(uuid4ToTopicSchema, senderCommunity)) - .setRecipientCommunity(v.parse(uuid4ToTopicSchema, recipientCommunity)) + .setSenderCommunity(senderCommunity) + .setRecipientCommunity(recipientCommunity) } builder.sign(senderKeyPair) return builder diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts index ee85b5cea..7be2cd4f2 100644 --- a/dlt-connector/src/schemas/account.schema.ts +++ b/dlt-connector/src/schemas/account.schema.ts @@ -1,12 +1,9 @@ import * as v from 'valibot' -import { uuidv4Schema } from './typeGuard.schema' +import { hieroIdSchema, uuidv4Schema } from './typeGuard.schema' // use code from transaction links export const identifierSeedSchema = v.object({ - seed: v.pipe( - v.string('expect string type'), - v.length(24, 'expect seed length 24') - ) + seed: v.pipe(v.string('expect string type'), v.length(24, 'expect seed length 24')), }) export type IdentifierSeed = v.InferOutput @@ -22,7 +19,7 @@ export type IdentifierCommunityAccount = v.InferOutput diff --git a/dlt-connector/src/schemas/base.schema.ts b/dlt-connector/src/schemas/base.schema.ts index 8a9f3af3d..2e065f55d 100644 --- a/dlt-connector/src/schemas/base.schema.ts +++ b/dlt-connector/src/schemas/base.schema.ts @@ -1,11 +1,9 @@ -import * as v from 'valibot' import { MemoryBlock } from 'gradido-blockchain-js' +import * as v from 'valibot' export const keyGenerationSeedSchema = v.pipe( v.string('expect string type'), v.hexadecimal('expect hexadecimal string'), v.length(64, 'expect seed length minimum 64 characters (32 Bytes)'), - v.transform( - (input: string) => MemoryBlock.fromHex(input), - ), -) \ No newline at end of file + v.transform((input: string) => MemoryBlock.fromHex(input)), +) diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index e7459175c..2c4da487a 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -1,10 +1,26 @@ -import { describe, it, expect } from 'bun:test' -import { transactionIdentifierSchema, transactionSchema, TransactionInput, memoSchema } from './transaction.schema' -import { InputTransactionType } from '../enum/InputTransactionType' -import { v4 as uuidv4 } from 'uuid' -import * as v from 'valibot' -import { GradidoUnit, DurationSeconds } from 'gradido-blockchain-js' +import { describe, expect, it, beforeAll } from 'bun:test' import { randomBytes } from 'crypto' +import { DurationSeconds, GradidoUnit } from 'gradido-blockchain-js' +import { v4 as uuidv4 } from 'uuid' +import { parse } from 'valibot' +import { InputTransactionType } from '../enum/InputTransactionType' +import { + TransactionInput, + transactionSchema, +} from './transaction.schema' +import { transactionIdentifierSchema } from '../client/GradidoNode/input.schema' +import { + gradidoAmountSchema, + HieroId, + hieroIdSchema, + HieroTransactionId, + hieroTransactionIdSchema, + Memo, + memoSchema, + timeoutDurationSchema, + Uuidv4, + uuidv4Schema +} from '../schemas/typeGuard.schema' const transactionLinkCode = (date: Date): string => { const time = date.getTime().toString(16) @@ -14,149 +30,154 @@ const transactionLinkCode = (date: Date): string => { .substring(0, 24 - time.length) + time ) } +let topic: HieroId +const topicString = '0.0.261' +let hieroTransactionId: HieroTransactionId +beforeAll(() => { + topic = parse(hieroIdSchema, topicString) + hieroTransactionId = parse(hieroTransactionIdSchema, '0.0.261-1755348116-1281621') +}) describe('transaction schemas', () => { - describe('transactionIdentifierSchema ', () => { it('valid, transaction identified by transactionNr and topic', () => { - expect(v.parse(transactionIdentifierSchema, { - transactionNr: 1, - iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' - })).toEqual({ - transactionNr: 1, - iotaMessageId: undefined, - iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + expect( + parse(transactionIdentifierSchema, { + transactionNr: 1, + topic: topicString, + }), + ).toEqual({ + transactionNr: 1, + hieroTransactionId: undefined, + topic, }) }) - it('valid, transaction identified by iotaMessageId and topic', () => { - expect(v.parse(transactionIdentifierSchema, { - iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', - iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' - })).toEqual({ - transactionNr: 0, - iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', - iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' + it('valid, transaction identified by hieroTransactionId and topic', () => { + expect( + parse(transactionIdentifierSchema, { + hieroTransactionId: '0.0.261-1755348116-1281621', + topic: topicString, + }), + ).toEqual({ + hieroTransactionId, + topic }) }) it('invalid, missing topic', () => { - expect(() => v.parse(transactionIdentifierSchema, { - transactionNr: 1, - iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', - })).toThrowError(new Error('Invalid key: Expected "iotaTopic" but received undefined')) + expect(() => + parse(transactionIdentifierSchema, { + transactionNr: 1, + hieroTransactionId: '0.0.261-1755348116-1281621', + }), + ).toThrowError(new Error('Invalid key: Expected "topic" but received undefined')) }) it('invalid, transactionNr and iotaMessageId set', () => { - expect(() => v.parse(transactionIdentifierSchema, { - transactionNr: 1, - iotaMessageId: '1b33a3cf7eb5dde04ed7ae571db1763006811ff6b7bb35b3d1c780de153af9dd', - iotaTopic: 'c00b210fc0a189df054eb9dafb584c527e9aeb537a62a35d44667f54529c73f5' - })).toThrowError(new Error('expect transactionNr or iotaMessageId not both')) + expect(() => + parse(transactionIdentifierSchema, { + transactionNr: 1, + hieroTransactionId: '0.0.261-1755348116-1281621', + topic + }), + ).toThrowError(new Error('expect transactionNr or hieroTransactionId not both')) }) }) - describe('transactionSchema', () => { + describe('transactionSchema', () => { + let userUuid: Uuidv4 + let userUuidString: string + let memoString: string + let memo: Memo + beforeAll(() => { + userUuidString = uuidv4() + userUuid = parse(uuidv4Schema, userUuidString) + memoString = 'TestMemo' + memo = parse(memoSchema, memoString) + }) it('valid, register new user address', () => { const registerAddress: TransactionInput = { - user: { - communityUuid: uuidv4(), - account: { - userUuid: uuidv4(), - } - }, - type: InputTransactionType.REGISTER_ADDRESS, + user: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + type: InputTransactionType.REGISTER_ADDRESS, createdAt: '2022-01-01T00:00:00.000Z', } - expect(v.parse(transactionSchema, registerAddress)).toEqual({ + expect(parse(transactionSchema, registerAddress)).toEqual({ user: { - communityUuid: registerAddress.user.communityUuid, + communityTopicId: topic, account: { - userUuid: registerAddress.user.account!.userUuid, - accountNr: 1, - } + userUuid, + accountNr: 0, + }, }, type: registerAddress.type, createdAt: new Date(registerAddress.createdAt), }) - }) + }) it('valid, gradido transfer', () => { - const communityUuid = uuidv4() const gradidoTransfer: TransactionInput = { - user: { - communityUuid, - account: { - userUuid: uuidv4(), - } - }, - linkedUser: { - communityUuid, - account: { - userUuid: uuidv4(), - } - }, - amount: '100', - memo: 'TestMemo', - type: InputTransactionType.GRADIDO_TRANSFER, - createdAt: '2022-01-01T00:00:00.000Z', - } - expect(v.parse(transactionSchema, gradidoTransfer)).toEqual({ user: { - communityUuid, - account: { - userUuid: gradidoTransfer.user.account!.userUuid, - accountNr: 1, - } + communityTopicId: topicString, + account: { userUuid: userUuidString }, }, linkedUser: { - communityUuid, - account: { - userUuid: gradidoTransfer.linkedUser!.account!.userUuid, - accountNr: 1, - } + communityTopicId: topicString, + account: { userUuid: userUuidString }, }, - amount: GradidoUnit.fromString(gradidoTransfer.amount!), - memo: gradidoTransfer.memo, + amount: '100', + memo: memoString, + type: InputTransactionType.GRADIDO_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + } + expect(parse(transactionSchema, gradidoTransfer)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + linkedUser: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + amount: parse(gradidoAmountSchema, gradidoTransfer.amount!), + memo, type: gradidoTransfer.type, createdAt: new Date(gradidoTransfer.createdAt), }) }) it('valid, gradido creation', () => { - const communityUuid = uuidv4() const gradidoCreation: TransactionInput = { - user: { - communityUuid, - account: { - userUuid: uuidv4(), - } - }, - linkedUser: { - communityUuid, - account: { - userUuid: uuidv4(), - } - }, - amount: '1000', - memo: 'For your help', - type: InputTransactionType.GRADIDO_CREATION, - createdAt: '2022-01-01T00:00:00.000Z', - targetDate: '2021-11-01T10:00' - } - expect(v.parse(transactionSchema, gradidoCreation)).toEqual({ user: { - communityUuid, - account: { - userUuid: gradidoCreation.user.account!.userUuid, - accountNr: 1, - } + communityTopicId: topicString, + account: { userUuid: userUuidString }, }, linkedUser: { - communityUuid, - account: { - userUuid: gradidoCreation.linkedUser!.account!.userUuid, - accountNr: 1, - } + communityTopicId: topicString, + account: { userUuid: userUuidString }, }, - amount: GradidoUnit.fromString(gradidoCreation.amount!), - memo: gradidoCreation.memo, + amount: '1000', + memo: memoString, + type: InputTransactionType.GRADIDO_CREATION, + createdAt: '2022-01-01T00:00:00.000Z', + targetDate: '2021-11-01T10:00', + } + expect(parse(transactionSchema, gradidoCreation)).toEqual({ + user: { + communityTopicId: topic, + account: { userUuid, accountNr: 0 }, + }, + linkedUser: { + communityTopicId: topic, + account: { userUuid, accountNr: 0 }, + }, + amount: parse(gradidoAmountSchema, gradidoCreation.amount!), + memo, type: gradidoCreation.type, createdAt: new Date(gradidoCreation.createdAt), targetDate: new Date(gradidoCreation.targetDate!), @@ -164,44 +185,44 @@ describe('transaction schemas', () => { }) it('valid, gradido transaction link / deferred transfer', () => { const gradidoTransactionLink: TransactionInput = { - user: { - communityUuid: uuidv4(), - account: { - userUuid: uuidv4(), - } - }, - linkedUser: { - communityUuid: uuidv4(), - seed: { - seed: transactionLinkCode(new Date()), - } - }, - amount: '100', - memo: 'use link wisely', - type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, - createdAt: '2022-01-01T00:00:00.000Z', - timeoutDuration: 60*60*24*30, - } - expect(v.parse(transactionSchema, gradidoTransactionLink)).toEqual({ user: { - communityUuid: gradidoTransactionLink.user.communityUuid, + communityTopicId: topicString, account: { - userUuid: gradidoTransactionLink.user.account!.userUuid, - accountNr: 1, - } + userUuid: userUuidString, + }, }, linkedUser: { - communityUuid: gradidoTransactionLink.linkedUser!.communityUuid, + communityTopicId: topicString, + seed: { + seed: transactionLinkCode(new Date()), + }, + }, + amount: '100', + memo: memoString, + type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + timeoutDuration: 60 * 60 * 24 * 30, + } + expect(parse(transactionSchema, gradidoTransactionLink)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + linkedUser: { + communityTopicId: topic, seed: { seed: gradidoTransactionLink.linkedUser!.seed!.seed, - } + }, }, - amount: GradidoUnit.fromString(gradidoTransactionLink.amount!), - memo: gradidoTransactionLink.memo, + amount: parse(gradidoAmountSchema, gradidoTransactionLink.amount!), + memo, type: gradidoTransactionLink.type, createdAt: new Date(gradidoTransactionLink.createdAt), - timeoutDuration: new DurationSeconds(gradidoTransactionLink.timeoutDuration!), + timeoutDuration: parse(timeoutDurationSchema, gradidoTransactionLink.timeoutDuration!), }) }) }) -}) \ No newline at end of file +}) diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index ac654da5e..de75bda89 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -1,43 +1,66 @@ import * as v from 'valibot' -import { dateFromStringSchema } from './typeConverter.schema' -import { identifierAccountSchema } from './account.schema' import { InputTransactionType } from '../enum/InputTransactionType' -import { accountTypeToAddressTypeSchema } from './typeConverter.schema' - +import { + identifierAccountSchema, + identifierCommunityAccountSchema, + identifierSeedSchema, +} from './account.schema' +import { accountTypeSchema, addressTypeSchema, dateSchema } from './typeConverter.schema' +import { + gradidoAmountSchema, + hieroIdSchema, + memoSchema, + timeoutDurationSchema, +} from './typeGuard.schema' export const transactionSchema = v.object({ - user: identifierAccountScmhema, + user: identifierAccountSchema, linkedUser: v.nullish(identifierAccountSchema, undefined), - amount: v.nullish(amountToGradidoUnitSchema, undefined), + amount: v.nullish(gradidoAmountSchema, undefined), memo: v.nullish(memoSchema, undefined), type: v.enum(InputTransactionType), - createdAt: dateFromStringSchema, - targetDate: v.nullish(dateFromStringSchema, undefined), + createdAt: dateSchema, + targetDate: v.nullish(dateSchema, undefined), timeoutDuration: v.nullish(timeoutDurationSchema, undefined), - accountType: v.nullish(accountTypeToAddressTypeSchema, undefined), + accountType: v.nullish(accountTypeSchema, undefined), }) export type TransactionInput = v.InferInput export type Transaction = v.InferOutput +// if the account is identified by seed +export const seedAccountSchema = v.object({ + communityTopicId: hieroIdSchema, + seed: identifierSeedSchema, +}) + +// if the account is identified by userUuid and accountNr +export const userAccountSchema = v.object({ + communityTopicId: hieroIdSchema, + account: identifierCommunityAccountSchema, +}) + +export type UserAccountInput = v.InferInput +export type UserAccount = v.InferOutput + export const creationTransactionSchema = v.object({ - user: identifierAccountSchema, - linkedUser: identifierAccountSchema, - amount: amountToGradidoUnitSchema, + user: userAccountSchema, + linkedUser: userAccountSchema, + amount: gradidoAmountSchema, memo: memoSchema, - createdAt: dateFromStringSchema, - targetDate: dateFromStringSchema, + createdAt: dateSchema, + targetDate: dateSchema, }) export type CreationTransactionInput = v.InferInput export type CreationTransaction = v.InferOutput export const transferTransactionSchema = v.object({ - user: identifierAccountSchema, - linkedUser: identifierAccountSchema, - amount: amountToGradidoUnitSchema, + user: userAccountSchema, + linkedUser: userAccountSchema, + amount: gradidoAmountSchema, memo: memoSchema, - createdAt: dateFromStringSchema, + createdAt: dateSchema, }) export type TransferTransactionInput = v.InferInput @@ -45,23 +68,40 @@ export type TransferTransaction = v.InferOutput export type RegisterAddressTransaction = v.InferOutput - +// deferred transfer transaction: from user account to seed export const deferredTransferTransactionSchema = v.object({ - user: identifierAccountSchema, - linkedUser: identifierAccountSchema, - amount: amountToGradidoUnitSchema, + user: userAccountSchema, + linkedUser: seedAccountSchema, + amount: gradidoAmountSchema, memo: memoSchema, - createdAt: dateFromStringSchema, + createdAt: dateSchema, timeoutDuration: timeoutDurationSchema, }) -export type DeferredTransferTransactionInput = v.InferInput +export type DeferredTransferTransactionInput = v.InferInput< + typeof deferredTransferTransactionSchema +> export type DeferredTransferTransaction = v.InferOutput + +// redeem deferred transaction: from seed to user account +export const redeemDeferredTransferTransactionSchema = v.object({ + user: seedAccountSchema, + linkedUser: userAccountSchema, + amount: gradidoAmountSchema, + createdAt: dateSchema, +}) + +export type RedeemDeferredTransferTransactionInput = v.InferInput< + typeof redeemDeferredTransferTransactionSchema +> +export type RedeemDeferredTransferTransaction = v.InferOutput< + typeof redeemDeferredTransferTransactionSchema +> diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index 7537e3b59..2ec02d12e 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -1,14 +1,16 @@ - -import { accountTypeSchema, addressTypeSchema, confirmedTransactionSchema } from './typeConverter.schema' -import * as v from 'valibot' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' -import { dateSchema } from './typeConverter.schema' import { AddressType_COMMUNITY_AUF, AddressType_COMMUNITY_PROJECT } from 'gradido-blockchain-js' +import * as v from 'valibot' import { AccountType } from '../enum/AccountType' +import { + accountTypeSchema, + addressTypeSchema, + confirmedTransactionSchema, + dateSchema, +} from './typeConverter.schema' describe('basic.schema', () => { - describe('date', () => { it('from string', () => { const date = v.parse(dateSchema, '2021-01-01:10:10') @@ -45,9 +47,12 @@ describe('basic.schema', () => { expect(accountType).toBe(AccountType.COMMUNITY_AUF) }) }) - + it('confirmedTransactionSchema', () => { - const confirmedTransaction = v.parse(confirmedTransactionSchema, 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') + const confirmedTransaction = v.parse( + confirmedTransactionSchema, + 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + ) expect(confirmedTransaction.getId()).toBe(7) expect(confirmedTransaction.getConfirmedAt().getSeconds()).toBe(1609464130) expect(confirmedTransaction.getVersionNumber()).toBe('3.4') diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 4f6eb6b42..3fb6e55ba 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -1,21 +1,20 @@ -import { - AddressType as AddressType, - ConfirmedTransaction, -} from 'gradido-blockchain-js' -import { AccountType } from '../enum/AccountType' +import { AddressType, ConfirmedTransaction } from 'gradido-blockchain-js' import * as v from 'valibot' -import { confirmedTransactionFromBase64, isAddressType, toAddressType, toAccountType } from '../utils/typeConverter' +import { AccountType } from '../enum/AccountType' +import { + confirmedTransactionFromBase64, + isAddressType, + toAccountType, + toAddressType, +} from '../utils/typeConverter' /** * dateSchema for creating a date from string or Date object */ export const dateSchema = v.pipe( - v.union([ - v.string('expect valid date string'), - v.instance(Date, 'expect Date object') - ]), + v.union([v.string('expect valid date string'), v.instance(Date, 'expect Date object')]), v.transform((input) => { - let date: Date + let date: Date if (input instanceof Date) { date = input } else { @@ -25,7 +24,7 @@ export const dateSchema = v.pipe( throw new Error('invalid date') } return date - }) + }), ) /** @@ -39,7 +38,7 @@ export const addressTypeSchema = v.pipe( v.enum(AccountType, 'expect account type'), v.custom(isAddressType, 'expect AddressType'), ]), - v.transform((value) => toAddressType(value)), + v.transform((value) => toAddressType(value)), ) /** @@ -58,7 +57,7 @@ export const confirmedTransactionSchema = v.pipe( v.instance(ConfirmedTransaction, 'expect ConfirmedTransaction'), v.pipe( v.string('expect confirmed Transaction base64 as string type'), - v.base64('expect to be valid base64') + v.base64('expect to be valid base64'), ), ]), v.transform( @@ -70,5 +69,3 @@ export const confirmedTransactionSchema = v.pipe( }, ), ) - - diff --git a/dlt-connector/src/schemas/typeGuard.schema.test.ts b/dlt-connector/src/schemas/typeGuard.schema.test.ts index 27781c868..ecd9eca7a 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.test.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.test.ts @@ -1,7 +1,7 @@ -import { describe, it, expect } from 'bun:test' -import { uuidv4Schema, memoSchema } from './typeGuard.schema' -import * as v from 'valibot' +import { describe, expect, it } from 'bun:test' import { v4 as uuidv4 } from 'uuid' +import * as v from 'valibot' +import { memoSchema, uuidv4Schema } from './typeGuard.schema' describe('typeGuard.schema', () => { describe('Uuidv4', () => { @@ -14,7 +14,7 @@ describe('typeGuard.schema', () => { }) describe('Basic Type Schemas for transactions', () => { describe('Memo', () => { - it('min length', () => { + it('min length', () => { const memoValue = 'memo1' const memoValueParsed = v.parse(memoSchema, memoValue) expect(memoValueParsed.toString()).toBe(memoValue) @@ -30,8 +30,10 @@ describe('typeGuard.schema', () => { }) it('to long', () => { const memoValue = 's'.repeat(256) - expect(() => v.parse(memoSchema, memoValue)).toThrow(new Error('expect string length <= 255')) + expect(() => v.parse(memoSchema, memoValue)).toThrow( + new Error('expect string length <= 255'), + ) }) }) }) -}) \ No newline at end of file +}) diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts index d5a1a32dd..bddb7048f 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -1,24 +1,24 @@ /** - * # TypeGuards + * # TypeGuards * Expand TypeScript Default Types with custom type which a based on a default type (or class) * Use valibot, so we can describe the type and validate it easy at runtime * After transpiling TypeScript unique symbol are gone * Infos at opaque type in typescript: https://evertpot.com/opaque-ts-types/ - * + * * declare const validAmount: unique symbol * export type Amount = number & { [validAmount]: true }; * Can be compared with using `typedef int Amount;` in C/C++ - * Example: + * Example: * To create a instance of Amount: - * `const amount: Amount = v.parse(amountSchema, 1.21)` + * `const amount: Amount = v.parse(amountSchema, 1.21)` * must be called and ensure the value is valid * If it isn't valid, v.parse will throw an error * Alternatively v.safeParse can be used, this don't throw but it return null on error */ +import { DurationSeconds, GradidoUnit, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' import { validate, version } from 'uuid' import * as v from 'valibot' -import { MemoryBlock, DurationSeconds, GradidoUnit } from 'gradido-blockchain-js' /** * type guard for uuid v4 @@ -26,17 +26,15 @@ import { MemoryBlock, DurationSeconds, GradidoUnit } from 'gradido-blockchain-js * uuidv4 is used for communityUuid and userUuid */ declare const validUuidv4: unique symbol -export type Uuidv4 = string & { [validUuidv4]: true }; +export type Uuidv4 = string & { [validUuidv4]: true } export const uuidv4Schema = v.pipe( v.string('expect string type'), - v.custom((value) => - (typeof value === 'string' && validate(value) && version(value) === 4), - 'uuid v4 expected' - ), - v.transform( - (input: string) => input as Uuidv4, + v.custom( + (value) => typeof value === 'string' && validate(value) && version(value) === 4, + 'uuid v4 expected', ), + v.transform((input: string) => input as Uuidv4), ) export type Uuidv4Input = v.InferInput @@ -48,16 +46,30 @@ export type Uuidv4Input = v.InferInput */ declare const validMemoryBlock32: unique symbol -export type MemoryBlock32 = MemoryBlock & { [validMemoryBlock32]: true }; +export type MemoryBlock32 = MemoryBlockPtr & { [validMemoryBlock32]: true } export const memoryBlock32Schema = v.pipe( - v.instance(MemoryBlock, 'expect MemoryBlock type'), - v.custom( - (val): boolean => val instanceof MemoryBlock && val.size() === 32 && !val.isEmpty(), - 'expect MemoryBlock size = 32 and not empty' - ), - v.transform( - (input: MemoryBlock) => input as MemoryBlock32, + v.union([ + v.instance(MemoryBlock, 'expect MemoryBlock type'), + v.instance(MemoryBlockPtr, 'expect MemoryBlockPtr type'), + ]), + v.custom((val): boolean => { + if (val instanceof MemoryBlockPtr) { + return val.size() === 32 && !val.isEmpty() + } + if (val instanceof MemoryBlock) { + return val.size() === 32 && !val.isEmpty() + } + return false + }, 'expect MemoryBlock size = 32 and not empty'), + v.transform( + (input: MemoryBlock | MemoryBlockPtr) => { + let memoryBlock: MemoryBlockPtr = input as MemoryBlockPtr + if (input instanceof MemoryBlock) { + memoryBlock = MemoryBlock.createPtr(input) + } + return memoryBlock as MemoryBlock32 + }, ), ) @@ -68,7 +80,7 @@ export const memoryBlock32Schema = v.pipe( * hex32 is a hex string of length 64 (binary size = 32) */ declare const validHex32: unique symbol -export type Hex32 = string & { [validHex32]: true }; +export type Hex32 = string & { [validHex32]: true } export const hex32Schema = v.pipe( v.union([ @@ -79,40 +91,50 @@ export const hex32Schema = v.pipe( ), memoryBlock32Schema, ]), - v.transform( - (input: string | MemoryBlock32 | Hex32) => { - if (typeof input === 'string') { - return input as Hex32 - } - return input.convertToHex() as Hex32 - }, - ), + v.transform((input: string | MemoryBlock32 | Hex32) => { + if (typeof input === 'string') { + return input as Hex32 + } + return input.convertToHex() as Hex32 + }), ) export type Hex32Input = v.InferInput /** - * type guard for iota message id - * create with `v.parse(iotaMessageIdSchema, '822387692a7cfd3f07f25742e91e248af281d771ee03a432c2e178e5533f786c')` - * iota message id is a hex string of length 64 + * type guard for hiero id + * create with `v.parse(hieroIdSchema, '0.0.2')` + * hiero id is a hiero id of the form 0.0.2 */ -declare const validIotaMessageId: unique symbol -export type IotaMessageId = Hex32 & { [validIotaMessageId]: true }; +declare const validHieroId: unique symbol +export type HieroId = string & { [validHieroId]: true } -export const iotaMessageIdSchema = v.pipe( - v.union([ - v.pipe( - v.string('expect string type'), - v.hexadecimal('expect hexadecimal string'), - v.length(64, 'expect string length = 64'), - ), - memoryBlock32Schema, - ]), - v.transform( - (input: string | MemoryBlock32) => v.parse(hex32Schema, input) as IotaMessageId, - ), +export const hieroIdSchema = v.pipe( + v.string('expect hiero id type, three 64 Bit Numbers separated by . for example 0.0.2'), + v.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/), + v.transform((input: string) => input as HieroId), ) +export type HieroIdInput = v.InferInput + +/** + * type guard for hiero transaction id + * create with `v.parse(hieroTransactionIdSchema, '0.0.141760-1755138896-607329203')` + * hiero transaction id is a hiero transaction id of the form 0.0.141760-1755138896-607329203 + * basically it is a Hiero id with a timestamp seconds-nanoseconds since 1970-01-01T00:00:00Z + * seconds is int64, nanoseconds int32 + */ +declare const validHieroTransactionId: unique symbol +export type HieroTransactionId = string & { [validHieroTransactionId]: true } + +export const hieroTransactionIdSchema = v.pipe( + v.string('expect hiero transaction id type, for example 0.0.141760-1755138896-607329203'), + v.regex(/^[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-[0-9]+$/), + v.transform((input: string) => input as HieroTransactionId), +) + +export type HieroTransactionIdInput = v.InferInput + /** * type guard for memo * create with `v.parse(memoSchema, 'memo')` @@ -122,38 +144,36 @@ export const MEMO_MIN_CHARS = 5 export const MEMO_MAX_CHARS = 255 declare const validMemo: unique symbol -export type Memo = string & { [validMemo]: true }; +export type Memo = string & { [validMemo]: true } export const memoSchema = v.pipe( - v.string('expect string type'), + v.string('expect string type'), v.maxLength(MEMO_MAX_CHARS, `expect string length <= ${MEMO_MAX_CHARS}`), v.minLength(MEMO_MIN_CHARS, `expect string length >= ${MEMO_MIN_CHARS}`), - v.transform( - (input: string) => input as Memo, - ), + v.transform((input: string) => input as Memo), ) /** * type guard for timeout duration * create with `v.parse(timeoutDurationSchema, 123)` - * timeout duration is a number in seconds inside bounds + * timeout duration is a number in seconds inside bounds * [1 hour, 3 months] * for Transaction Links / Deferred Transactions * seconds starting from createdAt Date in which the transaction link can be redeemed */ -const LINKED_TRANSACTION_TIMEOUT_DURATION_MIN = 60*60 -const LINKED_TRANSACTION_TIMEOUT_DURATION_MAX = 60*60*24*31*3 +const LINKED_TRANSACTION_TIMEOUT_DURATION_MIN = 60 * 60 +const LINKED_TRANSACTION_TIMEOUT_DURATION_MAX = 60 * 60 * 24 * 31 * 3 declare const validTimeoutDuration: unique symbol -export type TimeoutDuration = DurationSeconds & { [validTimeoutDuration]: true }; +export type TimeoutDuration = DurationSeconds & { [validTimeoutDuration]: true } export const timeoutDurationSchema = v.pipe( - v.number('expect number type'), - v.minValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MIN, 'expect number >= 1 hour'), - v.maxValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MAX, 'expect number <= 3 months'), - v.transform( - (input: number) => new DurationSeconds(input) as TimeoutDuration, - ), + v.number('expect number type'), + v.minValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MIN, 'expect number >= 1 hour'), + v.maxValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MAX, 'expect number <= 3 months'), + v.transform( + (input: number) => new DurationSeconds(input) as TimeoutDuration, + ), ) /** @@ -162,14 +182,12 @@ export const timeoutDurationSchema = v.pipe( * amount is a string representing a positive decimal number, compatible with decimal.js */ declare const validAmount: unique symbol -export type Amount = string & { [validAmount]: true }; +export type Amount = string & { [validAmount]: true } export const amountSchema = v.pipe( - v.string('expect string type'), + v.string('expect string type'), v.regex(/^[0-9]+(\.[0-9]+)?$/, 'expect positive number'), - v.transform( - (input: string) => input as Amount, - ), + v.transform((input: string) => input as Amount), ) /** @@ -179,11 +197,11 @@ export const amountSchema = v.pipe( * GradidoUnit is native implemented in gradido-blockchain-js in c++ and has functions for decay calculation */ declare const validGradidoAmount: unique symbol -export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true }; +export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true } export const gradidoAmountSchema = v.pipe( amountSchema, v.transform( (input: Amount) => GradidoUnit.fromString(input) as GradidoAmount, ), -) \ No newline at end of file +) diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index b9bd3c06c..1a6ac945b 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,77 +1,75 @@ -import { initTRPC, TRPCError } from '@trpc/server' -import * as v from 'valibot' -import { identifierAccountSchema } from '../schemas/account.schema' -import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' -import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../config/const' -import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' -import { getAddressType } from '../client/GradidoNode/api' -import { Uuidv4Hash } from '../data/Uuidv4Hash' -import { hex32Schema } from '../schemas/typeGuard.schema' +import { Elysia, status } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' +import { getLogger } from 'log4js' +import * as v from 'valibot' +import { getAddressType } from '../client/GradidoNode/api' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' +import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' +import { SendToIotaContext } from '../interactions/sendToIota/SendToIota.context' +import { IdentifierAccount, identifierAccountSchema } from '../schemas/account.schema' +import { + accountIdentifierSeedSchema, + accountIdentifierUserSchema, + existSchema, +} from './input.schema' -export const t = initTRPC.create() -const publicProcedure = t.procedure const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) -export const appRouter = t.router({ - isAccountExist: publicProcedure - .input(identifierAccountSchema) - .output(v.boolean()) - .query(async ({ input: userIdentifier }) => { - const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(userIdentifier)) - const publicKey = accountKeyPair.getPublicKey() - if (!publicKey) { - throw new TRPCError({ - code: 'NOT_FOUND', - message: "couldn't calculate account key pair", - }) - } - - // ask gradido node server for account type, if type !== NONE account exist - const addressType = await getAddressType( - v.parse(hex32Schema, publicKey.get()), - new Uuidv4Hash(userIdentifier.communityUuid), - ) - logger.info('isAccountExist') - if(logger.isDebugEnabled()) { - logger.debug('params', userIdentifier) - } - return addressType !== AddressType_NONE - }), - - sendTransaction: publicProcedure - .input(transactionDraftSchema) - .output(v.instanceof(TransactionResult)) - .mutation(async ({ input: transactionDraft }) => { - try { - return await SendToIotaContext(transactionDraft) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error instanceof TransactionError) { - return new TransactionResult(error) - } else { - throw error - } - } - }) -}) - -/* - -async sendTransaction( - @Arg('data') - transactionDraft: TransactionDraft, - ): Promise { - try { - return await SendToIotaContext(transactionDraft) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error instanceof TransactionError) { - return new TransactionResult(error) - } else { - throw error - } - } +async function isAccountExist(identifierAccount: IdentifierAccount): Promise { + const startTime = Date.now() + const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(identifierAccount)) + const publicKey = accountKeyPair.getPublicKey() + if (!publicKey) { + throw status(404, "couldn't calculate account key pair") } - */ \ No newline at end of file + + // ask gradido node server for account type, if type !== NONE account exist + const addressType = await getAddressType( + publicKey.convertToHex(), + identifierAccount.communityTopicId, + ) + const endTime = Date.now() + logger.info( + `isAccountExist: ${addressType !== AddressType_NONE}, time used: ${endTime - startTime}ms`, + ) + if (logger.isDebugEnabled()) { + logger.debug('params', identifierAccount) + } + return addressType !== AddressType_NONE +} + +export const appRoutes = new Elysia() + .get( + '/isAccountExist/:communityTopicId/:userUuid/:accountNr', + async ({ params: { communityTopicId, userUuid, accountNr } }) => { + const accountIdentifier = v.parse(identifierAccountSchema, { + communityTopicId, + account: { userUuid, accountNr }, + }) + return { exists: await isAccountExist(accountIdentifier) } + }, + // validation schemas + { params: accountIdentifierUserSchema, response: existSchema }, + ) + .get( + '/isAccountExist/:communityTopicId/:seed', + async ({ params: { communityTopicId, seed } }) => { + const accountIdentifier = v.parse(identifierAccountSchema, { + communityTopicId, + seed: { seed }, + }) + return { exists: await isAccountExist(accountIdentifier) } + }, + // validation schemas + { params: accountIdentifierSeedSchema, response: existSchema }, + ) + .post( + '/sendTransaction', + async ({ body }) => { + const transactionDraft = v.parse(transactionDraftSchema, body) + return await SendToIotaContext(transactionDraft) + }, + // validation schemas + { body: transactionDraftSchema, response: v.instanceof(TransactionResult) }, + ) diff --git a/dlt-connector/src/server/input.schema.ts b/dlt-connector/src/server/input.schema.ts new file mode 100644 index 000000000..c6aa463e5 --- /dev/null +++ b/dlt-connector/src/server/input.schema.ts @@ -0,0 +1,19 @@ +import { TypeBoxFromValibot } from '@sinclair/typemap' +import { t } from 'elysia' +import { hieroIdSchema, uuidv4Schema } from '../schemas/typeGuard.schema' + +export const accountIdentifierUserSchema = t.Object({ + communityTopicId: TypeBoxFromValibot(hieroIdSchema), + userUuid: TypeBoxFromValibot(uuidv4Schema), + accountNr: t.Number().positive(), +}) + +// identifier for a gradido account created by transaction link / deferred transfer +export const accountIdentifierSeedSchema = t.Object({ + communityTopicId: TypeBoxFromValibot(hieroIdSchema), + seed: TypeBoxFromValibot(uuidv4Schema), +}) + +export const existSchema = t.Object({ + exists: t.Boolean(), +}) diff --git a/dlt-connector/src/utils/derivationHelper.test.ts b/dlt-connector/src/utils/derivationHelper.test.ts index 63e7b6993..994d36f28 100644 --- a/dlt-connector/src/utils/derivationHelper.test.ts +++ b/dlt-connector/src/utils/derivationHelper.test.ts @@ -1,6 +1,6 @@ -import { hardenDerivationIndex, HARDENED_KEY_BITMASK } from './derivationHelper' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' +import { HARDENED_KEY_BITMASK, hardenDerivationIndex } from './derivationHelper' describe('utils', () => { it('test bitmask for hardened keys', () => { diff --git a/dlt-connector/src/utils/network.ts b/dlt-connector/src/utils/network.ts index 8c4244c36..5f348c640 100644 --- a/dlt-connector/src/utils/network.ts +++ b/dlt-connector/src/utils/network.ts @@ -1,16 +1,16 @@ import net from 'node:net' import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../config/const' import { CONFIG } from '../config' +import { LOG4JS_BASE_CATEGORY } from '../config/const' export async function isPortOpen( - url: string, + url: string, timeoutMs: number = CONFIG.CONNECT_TIMEOUT_MS, ): Promise { return new Promise((resolve) => { const socket = new net.Socket() const { hostname, port } = new URL(url) - + // auto-destroy socket after timeout const timer = setTimeout(() => { socket.destroy() @@ -35,17 +35,19 @@ export async function isPortOpen( }) } -const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) export async function isPortOpenRetry( - url: string, + url: string, timeoutMs: number = CONFIG.CONNECT_TIMEOUT_MS, delayMs: number = CONFIG.CONNECT_RETRY_DELAY_MS, retries: number = CONFIG.CONNECT_RETRY_COUNT, ): Promise { for (let i = 0; i < retries; i++) { - if (await isPortOpen(url, timeoutMs)) return true + if (await isPortOpen(url, timeoutMs)) { + return true + } await wait(delayMs) } throw new Error(`${url} port is not open after ${retries} retries`) -} \ No newline at end of file +} diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index a1f912581..6ab72b069 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -1,17 +1,17 @@ -import { - ConfirmedTransaction, - MemoryBlock, - InteractionDeserialize, - DeserializeType_CONFIRMED_TRANSACTION, +import { + AddressType, AddressType_COMMUNITY_AUF, AddressType_COMMUNITY_GMW, AddressType_COMMUNITY_HUMAN, AddressType_COMMUNITY_PROJECT, AddressType_CRYPTO_ACCOUNT, - AddressType_SUBACCOUNT, AddressType_DEFERRED_TRANSFER, AddressType_NONE, - AddressType, + AddressType_SUBACCOUNT, + ConfirmedTransaction, + DeserializeType_CONFIRMED_TRANSACTION, + InteractionDeserialize, + MemoryBlock, } from 'gradido-blockchain-js' import { AccountType } from '../enum/AccountType' @@ -44,17 +44,22 @@ const accountToAddressMap: Record = { [AccountType.NONE]: AddressType_NONE, } -const addressToAccountMap: Record = Object.entries(accountToAddressMap).reduce((acc, [accKey, addrVal]) => { - acc[addrVal] = String(accKey) as AccountType - return acc; -}, {} as Record) +const addressToAccountMap: Record = Object.entries( + accountToAddressMap, +).reduce( + (acc, [accKey, addrVal]) => { + acc[addrVal] = String(accKey) as AccountType + return acc + }, + {} as Record, +) export function isAddressType(val: unknown): val is AddressType { return typeof val === 'number' && Object.keys(addressToAccountMap).includes(val.toString()) } export function isAccountType(val: unknown): val is AccountType { - return Object.values(AccountType).includes(val as AccountType); + return Object.values(AccountType).includes(val as AccountType) } export function toAddressType(input: AccountType | AddressType): AddressType { From e772bfa631f7893a3401f428e667c754a995df99 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 16 Aug 2025 17:51:43 +0200 Subject: [PATCH 027/226] fix tests usw. --- dlt-connector/bun.lock | 242 +-- dlt-connector/package.json | 16 +- .../src/client/backend/BackendClient.ts | 13 +- .../client/backend/community.schema.test.ts | 3 + dlt-connector/src/errors.ts | 2 +- .../UserKeyPairRole.test.ts | 1 - .../sendToIota/SendToIota.context.ts | 1 - .../src/schemas/transaction.schema.test.ts | 1 - dlt-connector/src/server/index.ts | 16 +- dlt-connector/src/server/input.schema.ts | 2 +- dlt-connector/yarn.lock | 1629 +++++++++++++++++ 11 files changed, 1671 insertions(+), 255 deletions(-) create mode 100644 dlt-connector/yarn.lock diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 5795142a4..85f80c6f2 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -4,17 +4,13 @@ "": { "name": "dlt-connector", "dependencies": { - "@iota/client": "^2.2.4", - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#9a5f392", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js", }, "devDependencies": { "@biomejs/biome": "2.0.0", - "@elysiajs/trpc": "^1.1.0", - "@elysiajs/websocket": "^0.2.8", "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", - "@trpc/server": "^11.4.3", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", "elysia": "1.3.8", @@ -25,13 +21,9 @@ "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "^1.1.0", - "zod": "^3.25.61", }, }, }, - "trustedDependencies": [ - "@iota/client", - ], "packages": { "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], @@ -223,10 +215,6 @@ "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], - "@elysiajs/trpc": ["@elysiajs/trpc@1.1.0", "", { "peerDependencies": { "elysia": ">= 1.1.0" } }, "sha512-M8QWC+Wa5Z5MWY/+uMQuwZ+JoQkp4jOc1ra4SncFy1zSjFGin59LO1AT0pE+DRJaFV17gha9y7cB6Q7GnaJEAw=="], - - "@elysiajs/websocket": ["@elysiajs/websocket@0.2.8", "", { "dependencies": { "nanoid": "^4.0.0", "raikiri": "^0.0.0-beta.3" }, "peerDependencies": { "elysia": ">= 0.2.2" } }, "sha512-K9KLmYL1SYuAV353GvmK0V9DG5w7XTOGsa1H1dGB5BUTzvBaMvnwNeqnJQ3cjf9V1c0EjQds0Ty4LfUFvV45jw=="], - "@ethersproject/abi": ["@ethersproject/abi@5.8.0", "", { "dependencies": { "@ethersproject/address": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/constants": "^5.8.0", "@ethersproject/hash": "^5.8.0", "@ethersproject/keccak256": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/strings": "^5.8.0" } }, "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q=="], "@ethersproject/abstract-provider": ["@ethersproject/abstract-provider@5.8.0", "", { "dependencies": { "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/networks": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/transactions": "^5.8.0", "@ethersproject/web": "^5.8.0" } }, "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg=="], @@ -275,8 +263,6 @@ "@hashgraph/sdk": ["@hashgraph/sdk@2.70.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.20.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-naml5lWgewD3Dh8z0K7NRuKpbOpDaxpxwcLjtB9RFVmATMDU3IShSzxy24k5tUgY/0ZE7XXfCKgIpdT7TxGKqQ=="], - "@iota/client": ["@iota/client@2.2.4", "", { "dependencies": { "neon-cli": "^0.8", "prebuild-install": "^6.1.2" } }, "sha512-6zjtqJgkSgrMUFLbxr9k+zXGnEVw6gjTFn5emN2nKpR78+mwW4jUXuNcy/M194bK4sLHjj0T0L4pRWJ6XTGaew=="], - "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], @@ -307,7 +293,7 @@ "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], - "@noble/curves": ["@noble/curves@1.9.6", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA=="], + "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], @@ -369,8 +355,6 @@ "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], - "@trpc/server": ["@trpc/server@11.4.4", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-VkJb2xnb4rCynuwlCvgPBh5aM+Dco6fBBIo6lWAdJJRYVwtyE5bxNZBgUvRRz/cFSEAy0vmzLxF7aABDJfK5Rg=="], - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -409,22 +393,18 @@ "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], - "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="], + "aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], - "are-we-there-yet": ["are-we-there-yet@1.1.7", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g=="], + "are-we-there-yet": ["are-we-there-yet@3.0.1", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg=="], "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "array-back": ["array-back@3.1.0", "", {}, "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="], - "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="], @@ -483,8 +463,6 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "builtins": ["builtins@1.0.3", "", {}, "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="], - "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -501,8 +479,6 @@ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], - "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], "chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="], @@ -511,16 +487,10 @@ "ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], - "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], - - "cli-width": ["cli-width@3.0.0", "", {}, "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="], - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "cmake-js": ["cmake-js@7.3.1", "", { "dependencies": { "axios": "^1.6.5", "debug": "^4", "fs-extra": "^11.2.0", "memory-stream": "^1.0.0", "node-api-headers": "^1.1.0", "npmlog": "^6.0.2", "rc": "^1.2.7", "semver": "^7.5.4", "tar": "^6.2.0", "url-join": "^4.0.1", "which": "^2.0.2", "yargs": "^17.7.2" }, "bin": { "cmake-js": "bin/cmake-js" } }, "sha512-aJtHDrTFl8qovjSSqXT9aC2jdGfmP8JQsPtjdLAXFfH1BF4/ImZ27Jx0R61TFg8Apc3pl6e2yBKMveAeRXx2Rw=="], - "code-point-at": ["code-point-at@1.1.0", "", {}, "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -531,12 +501,6 @@ "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], - "command-line-args": ["command-line-args@5.2.1", "", { "dependencies": { "array-back": "^3.1.0", "find-replace": "^3.0.0", "lodash.camelcase": "^4.3.0", "typical": "^4.0.0" } }, "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg=="], - - "command-line-commands": ["command-line-commands@3.0.2", "", { "dependencies": { "array-back": "^4.0.1" } }, "sha512-ac6PdCtdR6q7S3HN+JiVLIWGHY30PRYIEl2qPo+FuEuzwAUk0UYyimrngrg7FvF/mCr4Jgoqv5ZnHZgads50rw=="], - - "command-line-usage": ["command-line-usage@6.1.3", "", { "dependencies": { "array-back": "^4.0.2", "chalk": "^2.4.2", "table-layout": "^1.0.2", "typical": "^5.2.0" } }, "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw=="], - "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -551,8 +515,6 @@ "core-js-compat": ["core-js-compat@3.45.0", "", { "dependencies": { "browserslist": "^4.25.1" } }, "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA=="], - "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], - "cosmiconfig": ["cosmiconfig@5.2.1", "", { "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA=="], "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], @@ -565,8 +527,6 @@ "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - "decompress-response": ["decompress-response@4.2.1", "", { "dependencies": { "mimic-response": "^2.0.0" } }, "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw=="], - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], @@ -577,15 +537,13 @@ "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], - "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - "dotenv": ["dotenv@10.0.0", "", {}, "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.202", "", {}, "sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg=="], + "electron-to-chromium": ["electron-to-chromium@1.5.203", "", {}, "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -613,7 +571,7 @@ "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], - "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], @@ -625,12 +583,8 @@ "execspawn": ["execspawn@1.0.1", "", { "dependencies": { "util-extend": "^1.0.1" } }, "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg=="], - "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], - "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], - "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], - "fast-base64-decode": ["fast-base64-decode@1.0.0", "", {}, "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="], "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], @@ -647,8 +601,6 @@ "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], - "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], - "file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="], "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], @@ -657,8 +609,6 @@ "finalhandler": ["finalhandler@1.1.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" } }, "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="], - "find-replace": ["find-replace@3.0.0", "", { "dependencies": { "array-back": "^3.0.1" } }, "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ=="], - "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], @@ -685,7 +635,7 @@ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "gauge": ["gauge@2.7.4", "", { "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.0", "object-assign": "^4.1.0", "signal-exit": "^3.0.0", "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" } }, "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg=="], + "gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], @@ -697,10 +647,6 @@ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "git-config": ["git-config@0.0.7", "", { "dependencies": { "iniparser": "~1.0.5" } }, "sha512-LidZlYZXWzVjS+M3TEwhtYBaYwLeOZrXci1tBgqp/vDdZTBMl02atvwb6G35L64ibscYoPnxfbwwUS+VZAISLA=="], - - "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], @@ -713,8 +659,6 @@ "graphql-request": ["graphql-request@7.2.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A=="], - "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], @@ -739,8 +683,6 @@ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], @@ -755,10 +697,6 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "iniparser": ["iniparser@1.0.5", "", {}, "sha512-i40MWqgTU6h/70NtMsDVVDLjDYWwcIR1yIEVDPfxZIJno9z9L4s83p/V7vAu2i48Vj0gpByrkGFub7ko9XvPrw=="], - - "inquirer": ["inquirer@7.3.3", "", { "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" } }, "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA=="], - "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], @@ -775,8 +713,6 @@ "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], - "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], @@ -831,8 +767,6 @@ "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], - "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], @@ -847,8 +781,6 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "make-promises-safe": ["make-promises-safe@5.1.0", "", {}, "sha512-AfdZ49rtyhQR/6cqVKGoH7y4ql7XkS5HJI1lZm0/5N6CQosy1eYbBJ/qbhkKHzo17UH7M918Bysf6XB9f3kS1g=="], - "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], "marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="], @@ -897,10 +829,6 @@ "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - - "mimic-response": ["mimic-response@2.1.0", "", {}, "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="], - "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], "minimalistic-crypto-utils": ["minimalistic-crypto-utils@1.0.1", "", {}, "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="], @@ -919,21 +847,11 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "mute-stream": ["mute-stream@0.0.8", "", {}, "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="], - "nan": ["nan@2.23.0", "", {}, "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ=="], - "nanoid": ["nanoid@4.0.2", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw=="], - - "napi-build-utils": ["napi-build-utils@1.0.2", "", {}, "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="], - "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], - - "neon-cli": ["neon-cli@0.8.3", "", { "dependencies": { "chalk": "^4.1.0", "command-line-args": "^5.1.1", "command-line-commands": "^3.0.1", "command-line-usage": "^6.1.0", "git-config": "0.0.7", "handlebars": "^4.7.6", "inquirer": "^7.3.3", "make-promises-safe": "^5.1.0", "rimraf": "^3.0.2", "semver": "^7.3.2", "toml": "^3.0.0", "ts-typed-json": "^0.3.2", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" }, "bin": { "neon": "bin/cli.js" } }, "sha512-I44MB8PD0AEyFr/b5icR4sX1tsjdkb2T2uWEStG4Uf5C/jzalZPn7eazbQrW6KDyXNd8bc+LVuOr1v6CGTa1KQ=="], - - "node-abi": ["node-abi@2.30.1", "", { "dependencies": { "semver": "^5.4.1" } }, "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w=="], + "node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], @@ -953,30 +871,22 @@ "npm-which": ["npm-which@3.0.1", "", { "dependencies": { "commander": "^2.9.0", "npm-path": "^2.0.2", "which": "^1.2.10" }, "bin": { "npm-which": "bin/npm-which.js" } }, "sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A=="], - "npmlog": ["npmlog@4.1.2", "", { "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", "gauge": "~2.7.3", "set-blocking": "~2.0.0" } }, "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg=="], + "npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], - "number-is-nan": ["number-is-nan@1.0.1", "", {}, "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="], - "ob1": ["ob1@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ngwqewtdUzFyycomdbdIhFLjePPSOt1awKMUXQ0L7iLHgWEPF3DsCerblzjzfAUHaXuvE9ccJymWQ/4PNNqvnQ=="], - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], "on-finished": ["on-finished@2.3.0", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww=="], "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], - "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], - "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], @@ -1009,14 +919,10 @@ "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - "prebuild-install": ["prebuild-install@6.1.4", "", { "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^3.0.3", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ=="], - "prebuildify": ["prebuildify@github:einhornimmond/prebuildify#65d9445", { "dependencies": { "cmake-js": "^7.2.1", "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", "npm-run-path": "^3.1.0", "npm-which": "^3.0.1", "pump": "^3.0.0", "tar-fs": "^2.1.0" }, "bin": { "prebuildify": "./bin.js" } }, "einhornimmond-prebuildify-65d9445"], "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], - "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], "promise": ["promise@8.3.0", "", { "dependencies": { "asap": "~2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="], @@ -1035,8 +941,6 @@ "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], - "raikiri": ["raikiri@0.0.0-beta.8", "", {}, "sha512-cH/yfvkiGkN8IBB2MkRHikpPurTnd2sMkQ/xtGpXrp3O76P4ppcWPb+86mJaBDzKaclLnSX+9NnT79D7ifH4/w=="], - "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], @@ -1053,12 +957,10 @@ "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], - "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], - "reduce-flatten": ["reduce-flatten@2.0.0", "", {}, "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w=="], - "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="], @@ -1077,24 +979,16 @@ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], - "rfc4648": ["rfc4648@1.5.4", "", {}, "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg=="], "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "run-async": ["run-async@2.4.1", "", {}, "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="], - - "rxjs": ["rxjs@6.6.7", "", { "dependencies": { "tslib": "^1.9.0" } }, "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="], @@ -1115,28 +1009,16 @@ "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], - - "simple-get": ["simple-get@3.1.1", "", { "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA=="], - "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], "spark-md5": ["spark-md5@3.0.2", "", {}, "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="], - "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], - - "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], - - "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], - - "spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="], - "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], @@ -1153,7 +1035,7 @@ "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -1165,8 +1047,6 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "table-layout": ["table-layout@1.0.2", "", { "dependencies": { "array-back": "^4.0.1", "deep-extend": "~0.6.0", "typical": "^5.2.0", "wordwrapjs": "^4.0.0" } }, "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A=="], - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], "tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], @@ -1181,10 +1061,6 @@ "throat": ["throat@5.0.0", "", {}, "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="], - "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], - - "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], - "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -1193,26 +1069,16 @@ "token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="], - "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], - - "ts-typed-json": ["ts-typed-json@0.3.2", "", {}, "sha512-Tdu3BWzaer7R5RvBIJcg9r8HrTZgpJmsX+1meXMJzYypbkj8NK2oJN0yvm4Dp/Iv6tzFa/L5jKRmEVTga6K3nA=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "tweetnacl": ["tweetnacl@1.0.3", "", {}, "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="], "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], - "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], - "typical": ["typical@4.0.0", "", {}, "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="], - - "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], - "uint8array-extras": ["uint8array-extras@1.4.1", "", {}, "sha512-+NWHrac9dvilNgme+gP4YrBSumsaMZP0fNBtXXFIf33RLLKEcBUKaQZ7ULUbS0sBfcjxIZ4V96OTRkCbM7hxpw=="], "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], @@ -1245,10 +1111,6 @@ "valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="], - "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], - - "validate-npm-package-name": ["validate-npm-package-name@3.0.0", "", { "dependencies": { "builtins": "^1.0.3" } }, "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw=="], - "vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="], "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], @@ -1259,10 +1121,6 @@ "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], - "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], - - "wordwrapjs": ["wordwrapjs@4.0.1", "", { "dependencies": { "reduce-flatten": "^2.0.0", "typical": "^5.2.0" } }, "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA=="], - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], @@ -1299,26 +1157,12 @@ "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "chrome-launcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "chromium-edge-launcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cmake-js/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], "cmake-js/fs-extra": ["fs-extra@11.3.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g=="], - "cmake-js/npmlog": ["npmlog@6.0.2", "", { "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.3", "set-blocking": "^2.0.0" } }, "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg=="], - - "command-line-commands/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], - - "command-line-usage/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], - - "command-line-usage/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - - "command-line-usage/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], - "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "elliptic/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="], @@ -1329,10 +1173,6 @@ "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "gauge/string-width": ["string-width@1.0.2", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw=="], - - "gauge/strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="], - "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], "import-fresh/resolve-from": ["resolve-from@3.0.0", "", {}, "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="], @@ -1347,40 +1187,22 @@ "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "memory-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "metro/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], - "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], - "metro-source-map/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], - - "metro-symbolicate/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], - "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "node-abi/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], - "npm-path/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], "npm-which/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], - "prebuildify/node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], - - "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], - "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], - "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], - "rxjs/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], @@ -1389,52 +1211,24 @@ "send/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], - "stacktrace-parser/type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], - - "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - - "table-layout/array-back": ["array-back@4.0.2", "", {}, "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg=="], - - "table-layout/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], - "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], - "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "wordwrapjs/typical": ["typical@5.2.0", "", {}, "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg=="], + "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "cmake-js/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "cmake-js/npmlog/are-we-there-yet": ["are-we-there-yet@3.0.1", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg=="], - - "cmake-js/npmlog/gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], - - "command-line-usage/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], - - "command-line-usage/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], - "connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "gauge/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@1.0.0", "", { "dependencies": { "number-is-nan": "^1.0.0" } }, "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw=="], - - "gauge/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], - "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "cmake-js/npmlog/are-we-there-yet/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "command-line-usage/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], - - "command-line-usage/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], - - "command-line-usage/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], } } diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 5bb4f4f08..450e13f42 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -8,7 +8,7 @@ "private": true, "scripts": { "start": "bun run src/index.ts", - "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --external=@iota/client", + "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify", "dev": "bun run --watch src/index.ts", "test": "bun test", "test:debug": "bun test --inspect-brk", @@ -17,17 +17,13 @@ "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#9a5f392", - "@iota/client": "^2.2.4" + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js" }, "devDependencies": { "@biomejs/biome": "2.0.0", - "@elysiajs/trpc": "^1.1.0", - "@elysiajs/websocket": "^0.2.8", "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", - "@trpc/server": "^11.4.3", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", "elysia": "1.3.8", @@ -37,14 +33,10 @@ "log4js": "^6.9.1", "typescript": "^5.8.3", "uuid": "^8.3.2", - "valibot": "^1.1.0", - "zod": "^3.25.61" + "valibot": "^1.1.0" }, "engines": { "node": ">=18" }, - "module": "src/index.js", - "trustedDependencies": [ - "@iota/client" - ] + "module": "src/index.js" } diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 7e98f82f9..ea076d9f0 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -1,10 +1,11 @@ -import { GraphQLClient, gql } from 'graphql-request' +import { GraphQLClient } from 'graphql-request' import { SignJWT } from 'jose' -import { getLogger, Logger } from 'log4js' -import * as v from 'valibot' + import { CONFIG } from '../../config' +import { communitySchema, type Community, homeCommunityGraphqlQuery } from './community.schema' +import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { type Community, communitySchema, homeCommunityGraphqlQuery } from './community.schema' +import * as v from 'valibot' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -15,7 +16,7 @@ import { type Community, communitySchema, homeCommunityGraphqlQuery } from './co export class BackendClient { private static instance: BackendClient client: GraphQLClient - logger: Logger + logger: Logger /** * The Singleton's constructor should always be private to prevent direct @@ -45,7 +46,7 @@ export class BackendClient { public static getInstance(): BackendClient | undefined { if (!BackendClient.instance) { BackendClient.instance = new BackendClient() - } + } return BackendClient.instance } diff --git a/dlt-connector/src/client/backend/community.schema.test.ts b/dlt-connector/src/client/backend/community.schema.test.ts index 4d2931ed0..d39c376ba 100644 --- a/dlt-connector/src/client/backend/community.schema.test.ts +++ b/dlt-connector/src/client/backend/community.schema.test.ts @@ -3,16 +3,19 @@ import { describe, expect, it } from 'bun:test' import * as v from 'valibot' import { uuidv4Schema } from '../../schemas/typeGuard.schema' import { communitySchema } from './community.schema' +import { hieroIdSchema } from '../../schemas/typeGuard.schema' describe('community.schema', () => { it('community', () => { expect( v.parse(communitySchema, { uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', + topicId: '0.0.4', foreign: false, createdAt: '2021-01-01', }), ).toEqual({ + topicId: v.parse(hieroIdSchema, '0.0.4'), uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), foreign: false, createdAt: new Date('2021-01-01'), diff --git a/dlt-connector/src/errors.ts b/dlt-connector/src/errors.ts index c9be7c2a2..e9cbaee98 100644 --- a/dlt-connector/src/errors.ts +++ b/dlt-connector/src/errors.ts @@ -1,5 +1,5 @@ +import { TransactionIdentifier } from './client/GradidoNode/input.schema' import { IdentifierAccount } from './schemas/account.schema' -import { TransactionIdentifier } from './schemas/transaction.schema' export class GradidoNodeError extends Error { constructor(message: string) { diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts index bf05b584c..fa12cdc48 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts @@ -1,6 +1,5 @@ import { beforeAll, describe, expect, it } from 'bun:test' import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { v4 as uuidv4 } from 'uuid' import { UserKeyPairRole } from './UserKeyPair.role' let communityKeyPair: KeyPairEd25519 diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index 288ccfc77..8371153c2 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import { GradidoTransaction, InteractionValidate, diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index 2c4da487a..e8d8326c6 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it, beforeAll } from 'bun:test' import { randomBytes } from 'crypto' -import { DurationSeconds, GradidoUnit } from 'gradido-blockchain-js' import { v4 as uuidv4 } from 'uuid' import { parse } from 'valibot' import { InputTransactionType } from '../enum/InputTransactionType' diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 1a6ac945b..7bf2a85c6 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,18 +1,21 @@ import { Elysia, status } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import * as v from 'valibot' +import { parse } from 'valibot' import { getAddressType } from '../client/GradidoNode/api' import { LOG4JS_BASE_CATEGORY } from '../config/const' import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' import { SendToIotaContext } from '../interactions/sendToIota/SendToIota.context' import { IdentifierAccount, identifierAccountSchema } from '../schemas/account.schema' +import { hieroTransactionIdSchema } from '../schemas/typeGuard.schema' import { accountIdentifierSeedSchema, accountIdentifierUserSchema, existSchema, } from './input.schema' +import { TypeBoxFromValibot } from '@sinclair/typemap' +import { transactionSchema } from '../schemas/transaction.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) @@ -43,7 +46,7 @@ export const appRoutes = new Elysia() .get( '/isAccountExist/:communityTopicId/:userUuid/:accountNr', async ({ params: { communityTopicId, userUuid, accountNr } }) => { - const accountIdentifier = v.parse(identifierAccountSchema, { + const accountIdentifier = parse(identifierAccountSchema, { communityTopicId, account: { userUuid, accountNr }, }) @@ -55,7 +58,7 @@ export const appRoutes = new Elysia() .get( '/isAccountExist/:communityTopicId/:seed', async ({ params: { communityTopicId, seed } }) => { - const accountIdentifier = v.parse(identifierAccountSchema, { + const accountIdentifier = parse(identifierAccountSchema, { communityTopicId, seed: { seed }, }) @@ -66,10 +69,7 @@ export const appRoutes = new Elysia() ) .post( '/sendTransaction', - async ({ body }) => { - const transactionDraft = v.parse(transactionDraftSchema, body) - return await SendToIotaContext(transactionDraft) - }, + async ({ body }) => await SendToIotaContext(parse(transactionSchema, body)), // validation schemas - { body: transactionDraftSchema, response: v.instanceof(TransactionResult) }, + { body: TypeBoxFromValibot(transactionSchema), response: TypeBoxFromValibot(hieroTransactionIdSchema) }, ) diff --git a/dlt-connector/src/server/input.schema.ts b/dlt-connector/src/server/input.schema.ts index c6aa463e5..336ade786 100644 --- a/dlt-connector/src/server/input.schema.ts +++ b/dlt-connector/src/server/input.schema.ts @@ -5,7 +5,7 @@ import { hieroIdSchema, uuidv4Schema } from '../schemas/typeGuard.schema' export const accountIdentifierUserSchema = t.Object({ communityTopicId: TypeBoxFromValibot(hieroIdSchema), userUuid: TypeBoxFromValibot(uuidv4Schema), - accountNr: t.Number().positive(), + accountNr: t.Number({ min: 0 }), }) // identifier for a gradido account created by transaction link / deferred transfer diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock new file mode 100644 index 000000000..f8d88875c --- /dev/null +++ b/dlt-connector/yarn.lock @@ -0,0 +1,1629 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@biomejs/biome@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.0.0.tgz#dc770781565640b9f884ad3d6d6383f64ca257c2" + integrity sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "2.0.0" + "@biomejs/cli-darwin-x64" "2.0.0" + "@biomejs/cli-linux-arm64" "2.0.0" + "@biomejs/cli-linux-arm64-musl" "2.0.0" + "@biomejs/cli-linux-x64" "2.0.0" + "@biomejs/cli-linux-x64-musl" "2.0.0" + "@biomejs/cli-win32-arm64" "2.0.0" + "@biomejs/cli-win32-x64" "2.0.0" + +"@biomejs/cli-darwin-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0.tgz#67135faa8bd52933fdaad09a160f9fc3a9defef3" + integrity sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw== + +"@biomejs/cli-darwin-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.0.0.tgz#49a7e064bad53e095d8a152b072adffcdeb4fb8e" + integrity sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw== + +"@biomejs/cli-linux-arm64-musl@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0.tgz#bfde27de8262a20e57e153f3807f47a01ccaeab3" + integrity sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA== + +"@biomejs/cli-linux-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.0.0.tgz#c2404b3869c03a6fa5a8b979755bc6dfd5a5ec47" + integrity sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw== + +"@biomejs/cli-linux-x64-musl@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0.tgz#8ab214ac7e21a2af29435439145888c50f2bdd2f" + integrity sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA== + +"@biomejs/cli-linux-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.0.0.tgz#cbd172ead9e5bba8cd590d06e6e548445cf7ab2a" + integrity sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg== + +"@biomejs/cli-win32-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.0.0.tgz#4677f4e034b3f4906e448b704f3314b38062a111" + integrity sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw== + +"@biomejs/cli-win32-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.0.0.tgz#f460a6950235c8f4bbd4cc405b210fec5cdb8ac9" + integrity sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg== + +"@ethersproject/abi@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.8.0.tgz#e79bb51940ac35fe6f3262d7fe2cdb25ad5f07d9" + integrity sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/hash" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/abstract-provider@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz#7581f9be601afa1d02b95d26b9d9840926a35b0c" + integrity sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/networks" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/transactions" "^5.8.0" + "@ethersproject/web" "^5.8.0" + +"@ethersproject/abstract-signer@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz#8d7417e95e4094c1797a9762e6789c7356db0754" + integrity sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== + dependencies: + "@ethersproject/abstract-provider" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + +"@ethersproject/address@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.8.0.tgz#3007a2c352eee566ad745dca1dbbebdb50a6a983" + integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + +"@ethersproject/base64@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.8.0.tgz#61c669c648f6e6aad002c228465d52ac93ee83eb" + integrity sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== + dependencies: + "@ethersproject/bytes" "^5.8.0" + +"@ethersproject/bignumber@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.8.0.tgz#c381d178f9eeb370923d389284efa19f69efa5d7" + integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.8.0.tgz#9074820e1cac7507a34372cadeb035461463be34" + integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/constants@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.8.0.tgz#12f31c2f4317b113a4c19de94e50933648c90704" + integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== + dependencies: + "@ethersproject/bignumber" "^5.8.0" + +"@ethersproject/hash@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.8.0.tgz#b8893d4629b7f8462a90102572f8cd65a0192b4c" + integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== + dependencies: + "@ethersproject/abstract-signer" "^5.8.0" + "@ethersproject/address" "^5.8.0" + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@ethersproject/keccak256@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.8.0.tgz#d2123a379567faf2d75d2aaea074ffd4df349e6a" + integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== + dependencies: + "@ethersproject/bytes" "^5.8.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.8.0.tgz#f0232968a4f87d29623a0481690a2732662713d6" + integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== + +"@ethersproject/networks@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.8.0.tgz#8b4517a3139380cba9fb00b63ffad0a979671fde" + integrity sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/properties@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.8.0.tgz#405a8affb6311a49a91dabd96aeeae24f477020e" + integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== + dependencies: + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/rlp@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.8.0.tgz#5a0d49f61bc53e051532a5179472779141451de5" + integrity sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/signing-key@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.8.0.tgz#9797e02c717b68239c6349394ea85febf8893119" + integrity sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + bn.js "^5.2.1" + elliptic "6.6.1" + hash.js "1.1.7" + +"@ethersproject/strings@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.8.0.tgz#ad79fafbf0bd272d9765603215ac74fd7953908f" + integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== + dependencies: + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + +"@ethersproject/transactions@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.8.0.tgz#1e518822403abc99def5a043d1c6f6fe0007e46b" + integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== + dependencies: + "@ethersproject/address" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/constants" "^5.8.0" + "@ethersproject/keccak256" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@ethersproject/signing-key" "^5.8.0" + +"@ethersproject/web@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.8.0.tgz#3e54badc0013b7a801463a7008a87988efce8a37" + integrity sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== + dependencies: + "@ethersproject/base64" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/logger" "^5.8.0" + "@ethersproject/properties" "^5.8.0" + "@ethersproject/strings" "^5.8.0" + +"@graphql-typed-document-node/core@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + +"@grpc/grpc-js@^1.12.6": + version "1.13.4" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.4.tgz#922fbc496e229c5fa66802d2369bf181c1df1c5a" + integrity sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.15" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" + integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + +"@hashgraph/cryptography@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@hashgraph/cryptography/-/cryptography-1.9.0.tgz#eda84887e5909a850b013575d87f8bdb9e9393f9" + integrity sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg== + dependencies: + "@noble/curves" "^1.8.1" + asn1js "^3.0.6" + bignumber.js "^9.1.1" + bn.js "^5.2.1" + buffer "^6.0.3" + crypto-js "^4.2.0" + forge-light "1.1.4" + js-base64 "^3.7.7" + react-native-get-random-values "^1.11.0" + spark-md5 "^3.0.2" + tweetnacl "^1.0.3" + utf8 "^3.0.0" + +"@hashgraph/proto@2.20.0": + version "2.20.0" + resolved "https://registry.yarnpkg.com/@hashgraph/proto/-/proto-2.20.0.tgz#4d1ef2c46b7cea8d0426163d5b145d20f7a627a8" + integrity sha512-XGIHRE9jr4wnnmCG8JeUD/nyeCiiYoUt35oRJz0QdCUwJYtbEsR6tPQxO90PxJJVDI5smT1c5i0f9wRRtFDhIA== + dependencies: + long "^5.2.3" + protobufjs "7.2.5" + +"@hashgraph/sdk@^2.70.0": + version "2.70.0" + resolved "https://registry.yarnpkg.com/@hashgraph/sdk/-/sdk-2.70.0.tgz#2dd8457e220f1babba0ccf91dc4085f275a2a7b6" + integrity sha512-naml5lWgewD3Dh8z0K7NRuKpbOpDaxpxwcLjtB9RFVmATMDU3IShSzxy24k5tUgY/0ZE7XXfCKgIpdT7TxGKqQ== + dependencies: + "@ethersproject/abi" "^5.8.0" + "@ethersproject/bignumber" "^5.8.0" + "@ethersproject/bytes" "^5.8.0" + "@ethersproject/rlp" "^5.8.0" + "@grpc/grpc-js" "^1.12.6" + "@hashgraph/cryptography" "1.9.0" + "@hashgraph/proto" "2.20.0" + bignumber.js "^9.1.1" + bn.js "^5.1.1" + crypto-js "^4.2.0" + js-base64 "^3.7.4" + long "^5.3.1" + pino "^9.6.0" + pino-pretty "^13.0.0" + protobufjs "7.2.5" + rfc4648 "^1.5.3" + utf8 "^3.0.0" + +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + +"@noble/curves@^1.8.1": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" + integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@sinclair/typebox@^0.34.33": + version "0.34.39" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.39.tgz#41db8ed5ff33fdd47cb34dab250c0eaea7a1a5be" + integrity sha512-keEoFsevmLwAedzacnTVmra66GViRH3fhWO1M+nZ8rUgpPJyN4mcvqlGr3QMrQXx4L8KNwW0q9/BeHSEoO4teg== + +"@sinclair/typemap@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@sinclair/typemap/-/typemap-0.10.1.tgz#5d1e5267ec535275c8adce21ace364f5d9c86ff7" + integrity sha512-UXR0fhu/n3c9B6lB+SLI5t1eVpt9i9CdDrp2TajRe3LbKiUhCTZN2kSfJhjPnpc3I59jMRIhgew7+0HlMi08mg== + +"@types/bun@^1.2.17": + version "1.2.20" + resolved "https://registry.yarnpkg.com/@types/bun/-/bun-1.2.20.tgz#2b7339f063a5a27a4ef10fd7d0f21095b578eee5" + integrity sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA== + dependencies: + bun-types "1.2.20" + +"@types/node@*", "@types/node@>=13.7.0": + version "24.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.3.0.tgz#89b09f45cb9a8ee69466f18ee5864e4c3eb84dec" + integrity sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow== + dependencies: + undici-types "~7.10.0" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +"aproba@^1.0.3 || ^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1" + integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew== + +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +asn1js@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.6.tgz#53e002ebe00c5f7fd77c1c047c3557d7c04dce25" + integrity sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.3" + tslib "^2.8.1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + +axios@^1.6.5: + version "1.11.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6" + integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.4" + proxy-from-env "^1.1.0" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bignumber.js@^9.1.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== + +bn.js@^5.1.1, bn.js@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bun-types@1.2.20: + version "1.2.20" + resolved "https://registry.yarnpkg.com/bun-types/-/bun-types-1.2.20.tgz#7ff3a05b2183fbe33d51c76ac99ae83aaf882988" + integrity sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA== + dependencies: + "@types/node" "*" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +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" + +cmake-js@^7.2.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.3.1.tgz#ed661eebd22a56d4743d7d2106a56fe50aa4355c" + integrity sha512-aJtHDrTFl8qovjSSqXT9aC2jdGfmP8JQsPtjdLAXFfH1BF4/ImZ27Jx0R61TFg8Apc3pl6e2yBKMveAeRXx2Rw== + dependencies: + axios "^1.6.5" + debug "^4" + fs-extra "^11.2.0" + memory-stream "^1.0.0" + node-api-headers "^1.1.0" + npmlog "^6.0.2" + rc "^1.2.7" + semver "^7.5.4" + tar "^6.2.0" + url-join "^4.0.1" + which "^2.0.2" + yargs "^17.7.2" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^2.0.7: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +cookie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +dateformat@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +debug@^4, debug@^4.3.3, debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +elliptic@6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +elysia@1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/elysia/-/elysia-1.3.8.tgz#66bd20f578ce936b0b29180cdb6afc2ef186ad3d" + integrity sha512-kxYFhegJbUEf5otzmisEvGt3R7d/dPBNVERO2nHo0kFqKBHyj5slArc90mSRKLfi1vamMtPcz67rL6Zeg5F2yg== + dependencies: + cookie "^1.0.2" + exact-mirror "0.1.3" + fast-decode-uri-component "^1.0.1" + optionalDependencies: + "@sinclair/typebox" "^0.34.33" + openapi-types "^12.1.3" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +exact-mirror@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/exact-mirror/-/exact-mirror-0.1.3.tgz#62fef6056a9bd808bca01ecd38f342f92ea9bb08" + integrity sha512-yI62LpSby0ItzPJF05C4DRycVAoknRiCIDOLOCCs9zaEKylOXQtOFM3flX54S44swpRz584vk3P70yWQodsLlg== + +execspawn@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/execspawn/-/execspawn-1.0.1.tgz#8286f9dde7cecde7905fbdc04e24f368f23f8da6" + integrity sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg== + dependencies: + util-extend "^1.0.1" + +fast-base64-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== + +fast-copy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35" + integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== + +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-redact@^3.1.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" + integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== + +fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +flatted@^3.2.7: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +follow-redirects@^1.14.4, follow-redirects@^1.15.6: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== + +forge-light@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/forge-light/-/forge-light-1.1.4.tgz#765da0d54e19c6644f37e7e5b873e1305ce78d1e" + integrity sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g== + +form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^11.2.0: + version "11.3.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.1.tgz#ba7a1f97a85f94c6db2e52ff69570db3671d5a74" + integrity sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + +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-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +"gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js": + version "0.0.1" + resolved "git+https://github.com/gradido/gradido-blockchain-js#9a5f392267bd313399b851e4dc6b5af7b959be3e" + dependencies: + bindings "^1.5.0" + nan "^2.20.0" + node-addon-api "^7.1.1" + node-gyp-build "^4.8.1" + prebuildify "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" + +graphql-request@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-7.2.0.tgz#af4aa25f27a087dd4fc93a4ff54a0f59c4487269" + integrity sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +help-me@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" + integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jose@^5.2.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/jose/-/jose-5.10.0.tgz#c37346a099d6467c401351a9a0c2161e0f52c4be" + integrity sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg== + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +js-base64@^3.7.4, js-base64@^3.7.7: + version "3.7.8" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4" + integrity sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow== + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" + integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonrpc-ts-client@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/jsonrpc-ts-client/-/jsonrpc-ts-client-0.2.3.tgz#ec50c413d84041564e6c8a4003ab4bb360d5cfcc" + integrity sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g== + dependencies: + axios "^0.24.0" + debug "^4.3.3" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +log4js@^6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + +long@^5.0.0, long@^5.2.3, long@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +memory-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/memory-stream/-/memory-stream-1.0.0.tgz#481dfd259ccdf57b03ec2c9632960044180e73c2" + integrity sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww== + dependencies: + readable-stream "^3.4.0" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nan@^2.20.0: + version "2.23.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.0.tgz#24aa4ddffcc37613a2d2935b97683c1ec96093c6" + integrity sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ== + +node-abi@^3.3.0: + version "3.75.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.75.0.tgz#2f929a91a90a0d02b325c43731314802357ed764" + integrity sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg== + dependencies: + semver "^7.3.5" + +node-addon-api@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + +node-api-headers@^1.1.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.5.0.tgz#73a0bab642c77e39b815b6d24ad4c6b56f695912" + integrity sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ== + +node-gyp-build@^4.8.1: + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +npm-path@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" + integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== + dependencies: + which "^1.2.10" + +npm-run-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + +npm-which@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" + integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== + dependencies: + commander "^2.9.0" + npm-path "^2.0.2" + which "^1.2.10" + +npmlog@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +openapi-types@^12.1.3: + version "12.1.3" + resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" + integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== + +path-key@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +pino-abstract-transport@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz#de241578406ac7b8a33ce0d77ae6e8a0b3b68a60" + integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw== + dependencies: + split2 "^4.0.0" + +pino-pretty@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-13.1.1.tgz#70130b9ff3737c8757f53e42d69e9f96835142b8" + integrity sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA== + dependencies: + colorette "^2.0.7" + dateformat "^4.6.3" + fast-copy "^3.0.2" + fast-safe-stringify "^2.1.1" + help-me "^5.0.0" + joycon "^3.1.1" + minimist "^1.2.6" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^2.0.0" + pump "^3.0.0" + secure-json-parse "^4.0.0" + sonic-boom "^4.0.1" + strip-json-comments "^5.0.2" + +pino-std-serializers@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" + integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== + +pino@^9.6.0: + version "9.9.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-9.9.0.tgz#0d2667ab4a54b561a4434a321ec595f305ab9cd1" + integrity sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.1.1" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^2.0.0" + pino-std-serializers "^7.0.0" + process-warning "^5.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^4.0.1" + thread-stream "^3.0.0" + +"prebuildify@git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2": + version "6.0.1" + resolved "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" + dependencies: + cmake-js "^7.2.1" + execspawn "^1.0.1" + minimist "^1.2.5" + mkdirp-classic "^0.5.3" + node-abi "^3.3.0" + npm-run-path "^3.1.0" + npm-which "^3.0.1" + pump "^3.0.0" + tar-fs "^2.1.0" + +process-warning@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" + integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== + +protobufjs@7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d" + integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +protobufjs@^7.2.5: + version "7.5.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" + integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +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.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-native-get-random-values@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz#1ca70d1271f4b08af92958803b89dccbda78728d" + integrity sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ== + dependencies: + fast-base64-decode "^1.0.0" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + +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== + +rfc4648@^1.5.3: + version "1.5.4" + resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.4.tgz#1174c0afba72423a0b70c386ecfeb80aa61b05ca" + integrity sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg== + +rfdc@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +secure-json-parse@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-4.0.0.tgz#2ee1b7581be38ab348bab5a3e49280ba80a89c85" + integrity sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA== + +semver@^7.3.5, semver@^7.5.4: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sonic-boom@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d" + integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww== + dependencies: + atomic-sleep "^1.0.0" + +spark-md5@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, 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== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" + integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +tar-fs@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" + integrity sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +thread-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-3.1.0.tgz#4b2ef252a7c215064507d4ef70c05a5e2d34c4f1" + integrity sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== + dependencies: + real-require "^0.2.0" + +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +typescript@^5.8.3: + version "5.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" + integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== + +undici-types@~7.10.0: + version "7.10.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350" + integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + +utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + integrity sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA== + +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== + +valibot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/valibot/-/valibot-1.1.0.tgz#873bb1af9e1577391690307bfe0520bd1360ec2d" + integrity sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw== + +which@^1.2.10: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.2: + 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" + +wide-align@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +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.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" From 5770feb11301bec14673bb21de790f857d18c033 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 3 Sep 2025 14:39:18 +0200 Subject: [PATCH 028/226] first adaptions to hiero --- .../src/graphql/input/EditCommunityInput.ts | 6 + backend/src/graphql/validator/HieroId.ts | 23 + dlt-connector/bun.lock | 202 +- .../src/client/GradidoNode/output.schema.ts | 0 dlt-connector/src/client/HieroClient.ts | 74 - .../src/client/backend/BackendClient.ts | 4 + .../src/client/backend/community.schema.ts | 2 +- dlt-connector/src/client/hiero/HieroClient.ts | 120 ++ .../src/client/hiero/output.schema.ts | 37 + dlt-connector/src/index.ts | 6 + .../sendToIota/SendToIota.context.ts | 2 +- dlt-connector/yarn.lock | 1629 ----------------- 12 files changed, 221 insertions(+), 1884 deletions(-) create mode 100644 backend/src/graphql/validator/HieroId.ts delete mode 100644 dlt-connector/src/client/GradidoNode/output.schema.ts delete mode 100644 dlt-connector/src/client/HieroClient.ts create mode 100644 dlt-connector/src/client/hiero/HieroClient.ts create mode 100644 dlt-connector/src/client/hiero/output.schema.ts delete mode 100644 dlt-connector/yarn.lock diff --git a/backend/src/graphql/input/EditCommunityInput.ts b/backend/src/graphql/input/EditCommunityInput.ts index 487221920..6607472bf 100644 --- a/backend/src/graphql/input/EditCommunityInput.ts +++ b/backend/src/graphql/input/EditCommunityInput.ts @@ -3,6 +3,7 @@ import { ArgsType, Field, InputType } from 'type-graphql' import { Location } from '@/graphql/model/Location' import { isValidLocation } from '@/graphql/validator/Location' +import { isValidHieroId } from '@/graphql/validator/HieroId' @ArgsType() @InputType() @@ -18,4 +19,9 @@ export class EditCommunityInput { @Field(() => Location, { nullable: true }) @isValidLocation() location?: Location | null + + @Field(() => String, { nullable: true }) + @isValidHieroId() + topicId?: string | null + } diff --git a/backend/src/graphql/validator/HieroId.ts b/backend/src/graphql/validator/HieroId.ts new file mode 100644 index 000000000..a7627ec78 --- /dev/null +++ b/backend/src/graphql/validator/HieroId.ts @@ -0,0 +1,23 @@ +import { ValidationArguments, ValidationOptions, registerDecorator } from 'class-validator' + +export function isValidHieroId(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + registerDecorator({ + name: 'isValidHieroId', + target: object.constructor, + propertyName, + options: validationOptions, + validator: { + validate(value: string) { + if (value.match(/[0-9]*\.[0-9]*\.[0-9]*/)) { + return true + } + return false + }, + defaultMessage(args: ValidationArguments) { + return `${propertyName} must be a valid HieroId (0.0.2121), ${args.property}` + }, + }, + }) + } +} diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 85f80c6f2..b300ad89a 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -35,48 +35,26 @@ "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], - "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg=="], - - "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ=="], - - "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="], - "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="], - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], - "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], - "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="], - - "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="], - - "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="], - "@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="], "@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], - "@babel/plugin-proposal-export-default-from": ["@babel/plugin-proposal-export-default-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw=="], - "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], "@babel/plugin-syntax-bigint": ["@babel/plugin-syntax-bigint@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg=="], @@ -85,20 +63,12 @@ "@babel/plugin-syntax-class-static-block": ["@babel/plugin-syntax-class-static-block@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw=="], - "@babel/plugin-syntax-dynamic-import": ["@babel/plugin-syntax-dynamic-import@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="], - - "@babel/plugin-syntax-export-default-from": ["@babel/plugin-syntax-export-default-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg=="], - - "@babel/plugin-syntax-flow": ["@babel/plugin-syntax-flow@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA=="], - "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww=="], "@babel/plugin-syntax-import-meta": ["@babel/plugin-syntax-import-meta@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g=="], "@babel/plugin-syntax-json-strings": ["@babel/plugin-syntax-json-strings@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA=="], - "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], - "@babel/plugin-syntax-logical-assignment-operators": ["@babel/plugin-syntax-logical-assignment-operators@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig=="], "@babel/plugin-syntax-nullish-coalescing-operator": ["@babel/plugin-syntax-nullish-coalescing-operator@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="], @@ -115,76 +85,6 @@ "@babel/plugin-syntax-top-level-await": ["@babel/plugin-syntax-top-level-await@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw=="], - "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], - - "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], - - "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="], - - "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="], - - "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q=="], - - "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], - - "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg=="], - - "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="], - - "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A=="], - - "@babel/plugin-transform-flow-strip-types": ["@babel/plugin-transform-flow-strip-types@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-flow": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg=="], - - "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], - - "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="], - - "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], - - "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw=="], - - "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="], - - "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="], - - "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="], - - "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="], - - "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA=="], - - "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="], - - "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="], - - "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], - - "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="], - - "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="], - - "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="], - - "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="], - - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], - - "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A=="], - - "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg=="], - - "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], - - "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="], - - "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="], - - "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg=="], - - "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], - "@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], @@ -259,9 +159,9 @@ "@hashgraph/cryptography": ["@hashgraph/cryptography@1.9.0", "", { "dependencies": { "@noble/curves": "^1.8.1", "asn1js": "^3.0.6", "bignumber.js": "^9.1.1", "bn.js": "^5.2.1", "buffer": "^6.0.3", "crypto-js": "^4.2.0", "forge-light": "1.1.4", "js-base64": "^3.7.7", "react-native-get-random-values": "^1.11.0", "spark-md5": "^3.0.2", "tweetnacl": "^1.0.3", "utf8": "^3.0.0" } }, "sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg=="], - "@hashgraph/proto": ["@hashgraph/proto@2.20.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "7.2.5" } }, "sha512-XGIHRE9jr4wnnmCG8JeUD/nyeCiiYoUt35oRJz0QdCUwJYtbEsR6tPQxO90PxJJVDI5smT1c5i0f9wRRtFDhIA=="], + "@hashgraph/proto": ["@hashgraph/proto@2.22.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "7.2.5" } }, "sha512-+h2qqk+KwpV+rr1AN4ip1Gel3X4v0DvFO9WH7o0ZR3gQX9pfzurptKGs30DlBnH21xPqDH61v90bZvVknE27NA=="], - "@hashgraph/sdk": ["@hashgraph/sdk@2.70.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.20.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-naml5lWgewD3Dh8z0K7NRuKpbOpDaxpxwcLjtB9RFVmATMDU3IShSzxy24k5tUgY/0ZE7XXfCKgIpdT7TxGKqQ=="], + "@hashgraph/sdk": ["@hashgraph/sdk@2.72.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.22.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-w35M77OAkJutENG4CldUGzfT+qubDjEYCQR5Ran75uHB+SLeCodR87AXWJ3ocr5vPaZ7lsflBXEYZLhgCi1G2g=="], "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], @@ -317,33 +217,25 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@react-native/assets-registry": ["@react-native/assets-registry@0.81.0", "", {}, "sha512-rZs8ziQ1YRV3Z5Mw5AR7YcgI3q1Ya9NIx6nyuZAT9wDSSjspSi+bww+Hargh/a4JfV2Ajcxpn9X9UiFJr1ddPw=="], + "@react-native/assets-registry": ["@react-native/assets-registry@0.81.1", "", {}, "sha512-o/AeHeoiPW8x9MzxE1RSnKYc+KZMW9b7uaojobEz0G8fKgGD1R8n5CJSOiQ/0yO2fJdC5wFxMMOgy2IKwRrVgw=="], - "@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.81.0", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.81.0" } }, "sha512-MEMlW91+2Kk9GiObRP1Nc6oTdiyvmSEbPMSC6kzUzDyouxnh5/x28uyNySmB2nb6ivcbmQ0lxaU059+CZSkKXQ=="], + "@react-native/codegen": ["@react-native/codegen@0.81.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-8KoUE1j65fF1PPHlAhSeUHmcyqpE+Z7Qv27A89vSZkz3s8eqWSRu2hZtCl0D3nSgS0WW0fyrIsFaRFj7azIiPw=="], - "@react-native/babel-preset": ["@react-native/babel-preset@0.81.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.81.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-RKMgCUGsso/2b32kgg24lB68LJ6qr2geLoSQTbisY6Usye0uXeXCgbZZDbILIX9upL4uzU4staMldRZ0v08F1g=="], + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.1", "", { "dependencies": { "@react-native/dev-middleware": "0.81.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-FuIpZcjBiiYcVMNx+1JBqTPLs2bUIm6X4F5enYGYcetNE2nfSMUVO8SGUtTkBdbUTfKesXYSYN8wungyro28Ag=="], - "@react-native/codegen": ["@react-native/codegen@0.81.0", "", { "dependencies": { "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, "peerDependencies": { "@babel/core": "*" } }, "sha512-gPFutgtj8YqbwKKt3YpZKamUBGd9YZJV51Jq2aiDZ9oThkg1frUBa20E+Jdi7jKn982wjBMxAklAR85QGQ4xMA=="], + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.1", "", {}, "sha512-dwKv1EqKD+vONN4xsfyTXxn291CNl1LeBpaHhNGWASK1GO4qlyExMs4TtTjN57BnYHikR9PzqPWcUcfzpVRaLg=="], - "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.0", "", { "dependencies": { "@react-native/dev-middleware": "0.81.0", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli"] }, "sha512-n04ACkCaLR54NmA/eWiDpjC16pHr7+yrbjQ6OEdRoXbm5EfL8FEre2kDAci7pfFdiSMpxdRULDlKpfQ+EV/GAQ=="], + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-hy3KlxNOfev3O5/IuyZSstixWo7E9FhljxKGHdvVtZVNjQdM+kPMh66mxeJbB2TjdJGAyBT4DjIwBaZnIFOGHQ=="], - "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.0", "", {}, "sha512-N/8uL2CGQfwiQRYFUNfmaYxRDSoSeOmFb56rb0PDnP3XbS5+X9ee7X4bdnukNHLGfkRdH7sVjlB8M5zE8XJOhw=="], + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.1", "", {}, "sha512-RpRxs/LbWVM9Zi5jH1qBLgTX746Ei+Ui4vj3FmUCd9EXUSECM5bJpphcsvqjxM5Vfl/o2wDLSqIoFkVP/6Te7g=="], - "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.0", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.0", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-J/HeC/+VgRyGECPPr9rAbe5S0OL6MCIrvrC/kgNKSME5+ZQLCiTpt3pdAoAMXwXiF9a02Nmido0DnyM1acXTIA=="], + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.1", "", {}, "sha512-w093OkHFfCnJKnkiFizwwjgrjh5ra53BU0ebPM3uBLkIQ6ZMNSCTZhG8ZHIlAYeIGtEinvmnSUi3JySoxuDCAQ=="], - "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.0", "", {}, "sha512-LGNtPXO1RKLws5ORRb4Q4YULi2qxM4qZRuARtwqM/1f2wyZVggqapoV0OXlaXaz+GiEd2ll3ROE4CcLN6J93jg=="], + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.1", "", {}, "sha512-TsaeZlE8OYFy3PSWc+1VBmAzI2T3kInzqxmwXoGU4w1d4XFkQFg271Ja9GmDi9cqV3CnBfqoF9VPwRxVlc/l5g=="], - "@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.0", "", {}, "sha512-whXZWIogzoGpqdyTjqT89M6DXmlOkWqNpWoVOAwVi8XFCMO+L7WTk604okIgO6gdGZcP1YtFpQf9JusbKrv/XA=="], + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-yG+zcMtyApW1yRwkNFvlXzEg3RIFdItuwr/zEvPCSdjaL+paX4rounpL0YX5kS9MsDIE5FXfcqINXg7L0xuwPg=="], - "@react-native/metro-babel-transformer": ["@react-native/metro-babel-transformer@0.81.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@react-native/babel-preset": "0.81.0", "hermes-parser": "0.29.1", "nullthrows": "^1.1.1" } }, "sha512-Mwovr4jJ3JTnbHEQLhdcMvS82LjijpqCydXl1aH2N16WVCrE5oSNFiqTt6NpZBw9zkJX7nijsY+xeCy6m+KK3Q=="], - - "@react-native/metro-config": ["@react-native/metro-config@0.81.0", "", { "dependencies": { "@react-native/js-polyfills": "0.81.0", "@react-native/metro-babel-transformer": "0.81.0", "metro-config": "^0.83.1", "metro-runtime": "^0.83.1" } }, "sha512-5eqLP4TCERHGRYDJSZa//O98CGDFNNEwHVvhs65Msfy6hAoSdw5pAAuTrsQwmbTBp0Fkvu7Bx8BZDhiferZsHg=="], - - "@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.0", "", {}, "sha512-3gEu/29uFgz+81hpUgdlOojM4rjHTIPwxpfygFNY60V6ywZih3eLDTS8kAjNZfPFHQbcYrNorJzwnL5yFF/uLw=="], - - "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.0", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-p14QC5INHkbMZ96158sUxkSwN6zp138W11G+CRGoLJY4Q9WRJBCe7wHR5Owyy3XczQXrIih/vxAXwgYeZ2XByg=="], - - "@sinclair/typebox": ["@sinclair/typebox@0.34.39", "", {}, "sha512-keEoFsevmLwAedzacnTVmra66GViRH3fhWO1M+nZ8rUgpPJyN4mcvqlGr3QMrQXx4L8KNwW0q9/BeHSEoO4teg=="], + "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], "@sinclair/typemap": ["@sinclair/typemap@0.10.1", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.30", "valibot": "^1.0.0", "zod": "^3.24.1" } }, "sha512-UXR0fhu/n3c9B6lB+SLI5t1eVpt9i9CdDrp2TajRe3LbKiUhCTZN2kSfJhjPnpc3I59jMRIhgew7+0HlMi08mg=="], @@ -363,7 +255,7 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="], + "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="], @@ -375,7 +267,7 @@ "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], - "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="], + "@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="], "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], @@ -423,16 +315,8 @@ "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@29.6.3", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg=="], - "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="], - - "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="], - - "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="], - "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], - "babel-plugin-transform-flow-enums": ["babel-plugin-transform-flow-enums@0.0.2", "", { "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" } }, "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ=="], - "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], "babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="], @@ -455,7 +339,7 @@ "brorand": ["brorand@1.1.0", "", {}, "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="], - "browserslist": ["browserslist@4.25.2", "", { "dependencies": { "caniuse-lite": "^1.0.30001733", "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA=="], + "browserslist": ["browserslist@4.25.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg=="], "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], @@ -463,7 +347,7 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="], + "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -475,7 +359,7 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001735", "", {}, "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w=="], + "caniuse-lite": ["caniuse-lite@1.0.30001739", "", {}, "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -513,8 +397,6 @@ "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - "core-js-compat": ["core-js-compat@3.45.0", "", { "dependencies": { "browserslist": "^4.25.1" } }, "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA=="], - "cosmiconfig": ["cosmiconfig@5.2.1", "", { "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA=="], "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], @@ -543,7 +425,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.203", "", {}, "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g=="], + "electron-to-chromium": ["electron-to-chromium@1.5.213", "", {}, "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -653,7 +535,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#9a5f392", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-9a5f392"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#eccade8", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-eccade8"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], @@ -701,8 +583,6 @@ "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - "is-directory": ["is-directory@0.3.1", "", {}, "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw=="], "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], @@ -769,8 +649,6 @@ "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], - "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], - "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="], "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], @@ -903,13 +781,11 @@ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pino": ["pino@9.9.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ=="], + "pino": ["pino@9.9.1", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-40SszWPOPwGhUIJ3zj0PsbMNV1bfg8nw5Qp/tP2FE2p3EuycmhDeYimKOMBAu6rtxcSw2QpjJsuK5A6v+en8Yw=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], @@ -951,7 +827,7 @@ "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "react-native": ["react-native@0.81.0", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.0", "@react-native/codegen": "0.81.0", "@react-native/community-cli-plugin": "0.81.0", "@react-native/gradle-plugin": "0.81.0", "@react-native/js-polyfills": "0.81.0", "@react-native/normalize-colors": "0.81.0", "@react-native/virtualized-lists": "0.81.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-RDWhewHGsAa5uZpwIxnJNiv5tW2y6/DrQUjEBdAHPzGMwuMTshern2s4gZaWYeRU3SQguExVddCjiss9IBhxqA=="], + "react-native": ["react-native@0.81.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.1", "@react-native/codegen": "0.81.1", "@react-native/community-cli-plugin": "0.81.1", "@react-native/gradle-plugin": "0.81.1", "@react-native/js-polyfills": "0.81.1", "@react-native/normalize-colors": "0.81.1", "@react-native/virtualized-lists": "0.81.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-k2QJzWc/CUOwaakmD1SXa4uJaLcwB2g2V9BauNIjgtXYYAeyFjx9jlNz/+wAEcHLg9bH5mgMdeAwzvXqjjh9Hg=="], "react-native-get-random-values": ["react-native-get-random-values@1.11.0", "", { "dependencies": { "fast-base64-decode": "^1.0.0" }, "peerDependencies": { "react-native": ">=0.56" } }, "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ=="], @@ -961,22 +837,10 @@ "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], - "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], - - "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="], - "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], - "regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="], - - "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], - - "regjsparser": ["regjsparser@0.12.0", "", { "dependencies": { "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ=="], - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], - "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], "rfc4648": ["rfc4648@1.5.4", "", {}, "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg=="], @@ -1045,15 +909,13 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], "tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], - "terser": ["terser@5.43.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="], + "terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="], "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], @@ -1079,18 +941,10 @@ "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], - "uint8array-extras": ["uint8array-extras@1.4.1", "", {}, "sha512-+NWHrac9dvilNgme+gP4YrBSumsaMZP0fNBtXXFIf33RLLKEcBUKaQZ7ULUbS0sBfcjxIZ4V96OTRkCbM7hxpw=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], - "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], - - "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], - - "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.0", "", {}, "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg=="], - - "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.1.0", "", {}, "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w=="], - "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], @@ -1143,18 +997,10 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], "@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], - "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -1201,8 +1047,6 @@ "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], - "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], diff --git a/dlt-connector/src/client/GradidoNode/output.schema.ts b/dlt-connector/src/client/GradidoNode/output.schema.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/dlt-connector/src/client/HieroClient.ts b/dlt-connector/src/client/HieroClient.ts deleted file mode 100644 index d7be17eb3..000000000 --- a/dlt-connector/src/client/HieroClient.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - AccountBalance, - AccountBalanceQuery, - Client, - LocalProvider, - PrivateKey, - TopicMessageSubmitTransaction, - TransactionReceipt, - TransactionResponse, - Wallet, -} from '@hashgraph/sdk' -import { GradidoTransaction } from 'gradido-blockchain-js' -import { getLogger, Logger } from 'log4js' -import { CONFIG } from '../config' -import { LOG4JS_BASE_CATEGORY } from '../config/const' -import { HieroId } from '../schemas/typeGuard.schema' - -export class HieroClient { - private static instance: HieroClient - wallet: Wallet - logger: Logger - - private constructor() { - this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) - const provider = LocalProvider.fromClient(Client.forName(CONFIG.HIERO_HEDERA_NETWORK)) - let operatorKey: PrivateKey - if (CONFIG.HIERO_OPERATOR_KEY.length === 64) { - operatorKey = PrivateKey.fromStringED25519(CONFIG.HIERO_OPERATOR_KEY) - } else { - operatorKey = PrivateKey.fromStringECDSA(CONFIG.HIERO_OPERATOR_KEY) - } - this.wallet = new Wallet(CONFIG.HIERO_OPERATOR_ID, operatorKey, provider) - } - - public static getInstance(): HieroClient { - if (!CONFIG.HIERO_ACTIVE) { - throw new Error('hiero is disabled via config...') - } - if (!HieroClient.instance) { - HieroClient.instance = new HieroClient() - } - - return HieroClient.instance - } - - public async sendMessage( - topicId: HieroId, - transaction: GradidoTransaction, - ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { - const serializedTransaction = transaction.getSerializedTransaction() - if (!serializedTransaction) { - throw new Error('cannot serialize transaction') - } - // send one message - const hieroTransaction = await new TopicMessageSubmitTransaction({ - topicId, - message: serializedTransaction.data(), - }).freezeWithSigner(this.wallet) - const signedHieroTransaction = await hieroTransaction.signWithSigner(this.wallet) - const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) - const sendReceipt = await sendResponse.getReceiptWithSigner(this.wallet) - this.logger.info( - `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, - ) - return { receipt: sendReceipt, response: sendResponse } - } - - public async getBalance(): Promise { - const balance = await new AccountBalanceQuery() - .setAccountId(this.wallet.getAccountId()) - .executeWithSigner(this.wallet) - return balance - } -} diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index ea076d9f0..5e2bec24f 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -63,6 +63,10 @@ export class BackendClient { return v.parse(communitySchema, data.homeCommunity) } + public async setHomeCommunityTopicId(topicId: HieroId) { + + } + private async getRequestHeader(): Promise<{ authorization: string }> { diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts index 182a41368..4c99f10b4 100644 --- a/dlt-connector/src/client/backend/community.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -12,7 +12,7 @@ import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' */ export const communitySchema = v.object({ uuid: uuidv4Schema, - topicId: hieroIdSchema, + topicId: v.optional(hieroIdSchema, ''), foreign: v.boolean('expect boolean type'), createdAt: dateSchema, }) diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts new file mode 100644 index 000000000..10fa23592 --- /dev/null +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -0,0 +1,120 @@ +import { + AccountBalance, + AccountBalanceQuery, + Client, + LocalProvider, + PrivateKey, + Timestamp, + TopicCreateTransaction, + TopicId, + TopicInfoQuery, + TopicMessageSubmitTransaction, + TopicUpdateTransaction, + TransactionReceipt, + TransactionResponse, + Wallet, +} from '@hashgraph/sdk' +import { parse } from 'valibot' +import { GradidoTransaction, HieroTopicId } from 'gradido-blockchain-js' +import { getLogger, Logger } from 'log4js' +import { CONFIG } from '../../config' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { topicInfoSchema, type TopicInfoOutput } from './output.schema' + +// https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic +export const MIN_AUTORENEW_PERIOD = 6999999 //seconds +export const MAX_AUTORENEW_PERIOD = 8000001 // seconds + +export class HieroClient { + private static instance: HieroClient + wallet: Wallet + client: Client + logger: Logger + + private constructor() { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) + this.client = Client.forName(CONFIG.HIERO_HEDERA_NETWORK) + const provider = LocalProvider.fromClient(this.client) + let operatorKey: PrivateKey + if (CONFIG.HIERO_OPERATOR_KEY.length === 64) { + operatorKey = PrivateKey.fromStringED25519(CONFIG.HIERO_OPERATOR_KEY) + } else { + operatorKey = PrivateKey.fromStringECDSA(CONFIG.HIERO_OPERATOR_KEY) + } + this.wallet = new Wallet(CONFIG.HIERO_OPERATOR_ID, operatorKey, provider) + } + + public static getInstance(): HieroClient { + if (!CONFIG.HIERO_ACTIVE) { + throw new Error('hiero is disabled via config...') + } + if (!HieroClient.instance) { + HieroClient.instance = new HieroClient() + } + + return HieroClient.instance + } + + public async sendMessage( + topicId: HieroId, + transaction: GradidoTransaction, + ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { + const serializedTransaction = transaction.getSerializedTransaction() + if (!serializedTransaction) { + throw new Error('cannot serialize transaction') + } + // send one message + const hieroTransaction = await new TopicMessageSubmitTransaction({ + topicId, + message: serializedTransaction.data(), + }).freezeWithSigner(this.wallet) + const signedHieroTransaction = await hieroTransaction.signWithSigner(this.wallet) + const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) + const sendReceipt = await sendResponse.getReceiptWithSigner(this.wallet) + this.logger.info( + `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, + ) + return { receipt: sendReceipt, response: sendResponse } + } + + public async getBalance(): Promise { + const balance = await new AccountBalanceQuery() + .setAccountId(this.wallet.getAccountId()) + .executeWithSigner(this.wallet) + return balance + } + + public async getTopicInfo(topicId: HieroTopicId): Promise { + const info = await new TopicInfoQuery() + .setTopicId(new TopicId(topicId.getShardNum(), topicId.getRealmNum(), topicId.getTopicNum())) + .execute(this.client) + this.logger.debug(JSON.stringify(info, null, 2)) + return parse(topicInfoSchema, { + topicId: topicId.toString(), + sequenceNumber: info.sequenceNumber.toNumber(), + expirationTime: info.expirationTime?.toString(), + autoRenewPeriod: info.autoRenewPeriod?.seconds, + autoRenewAccountId: info.autoRenewAccountId?.toString(), + }) + } + + public async createTopic(): Promise { + let transaction = await new TopicCreateTransaction().freezeWithSigner(this.wallet) + transaction = await transaction.signWithSigner(this.wallet) + const createResponse = await transaction.executeWithSigner(this.wallet) + const createReceipt = await createResponse.getReceiptWithSigner(this.wallet) + this.logger.debug(createReceipt.toString()) + return parse(hieroIdSchema, createReceipt.topicId?.toString()) + } + + public async updateTopic(): Promise { + let transaction = new TopicUpdateTransaction() + transaction.setExpirationTime(new Date(new Date().getTime() + MIN_AUTORENEW_PERIOD * 1000)) + transaction = await transaction.freezeWithSigner(this.wallet) + transaction = await transaction.signWithSigner(this.wallet) + const updateResponse = await transaction.executeWithSigner(this.wallet) + const updateReceipt = await updateResponse.getReceiptWithSigner(this.wallet) + this.logger.debug(updateReceipt.toString()) + } +} diff --git a/dlt-connector/src/client/hiero/output.schema.ts b/dlt-connector/src/client/hiero/output.schema.ts new file mode 100644 index 000000000..3f0218010 --- /dev/null +++ b/dlt-connector/src/client/hiero/output.schema.ts @@ -0,0 +1,37 @@ +import * as v from 'valibot' +import { hieroIdSchema } from '../../schemas/typeGuard.schema' + +// schema definitions for exporting data from hiero request as json back to caller +/*export const dateStringSchema = v.pipe( + v.enum([v.string(), v.date()], + v.transform(in: string | Date) + +)*/ +export const dateStringSchema = v.pipe( + v.union([v.string('expect valid date string'), v.instance(Date, 'expect Date object')]), + v.transform((input) => { + let date: Date + if (input instanceof Date) { + date = input + } else { + date = new Date(input) + } + if (isNaN(date.getTime())) { + throw new Error('invalid date') + } + return date.toISOString() + }), +) + +export const positiveNumberSchema = v.pipe(v.number(), v.minValue(0)) + +export const topicInfoSchema = v.object({ + topicId: hieroIdSchema, + sequenceNumber: positiveNumberSchema, + expirationTime: dateStringSchema, + autoRenewPeriod: v.optional(positiveNumberSchema, 0), + autoRenewAccountId: v.optional(hieroIdSchema, '0.0.0'), +}) + +export type TopicInfoOutput = v.InferOutput + diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 68b7f4803..5ea9faa2e 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -4,6 +4,7 @@ import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { configure, getLogger } from 'log4js' import * as v from 'valibot' import { BackendClient } from './client/backend/BackendClient' +import { HieroClient } from './client/hiero/HieroClient' import { getTransaction } from './client/GradidoNode/api' import { CONFIG } from './config' import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' @@ -38,6 +39,11 @@ async function main() { // wait for backend server await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) const homeCommunity = await backend.getHomeCommunityDraft() + // on missing topicId, create one + if (!homeCommunity.topicId) { + const topicId = await HieroClient.getInstance().createTopic() + + } KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.topicId) logger.info('home community topic: %s', homeCommunity.topicId) logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts index 8371153c2..4b8b32c34 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts @@ -7,7 +7,7 @@ import { import { getLogger } from 'log4js' import { safeParse, parse } from 'valibot' import { Community, communitySchema } from '../../client/backend/community.schema' -import { HieroClient } from '../../client/HieroClient' +import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Transaction, transactionSchema } from '../../schemas/transaction.schema' import { HieroId, HieroTransactionId, hieroTransactionIdSchema } from '../../schemas/typeGuard.schema' diff --git a/dlt-connector/yarn.lock b/dlt-connector/yarn.lock deleted file mode 100644 index f8d88875c..000000000 --- a/dlt-connector/yarn.lock +++ /dev/null @@ -1,1629 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@biomejs/biome@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.0.0.tgz#dc770781565640b9f884ad3d6d6383f64ca257c2" - integrity sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ== - optionalDependencies: - "@biomejs/cli-darwin-arm64" "2.0.0" - "@biomejs/cli-darwin-x64" "2.0.0" - "@biomejs/cli-linux-arm64" "2.0.0" - "@biomejs/cli-linux-arm64-musl" "2.0.0" - "@biomejs/cli-linux-x64" "2.0.0" - "@biomejs/cli-linux-x64-musl" "2.0.0" - "@biomejs/cli-win32-arm64" "2.0.0" - "@biomejs/cli-win32-x64" "2.0.0" - -"@biomejs/cli-darwin-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0.tgz#67135faa8bd52933fdaad09a160f9fc3a9defef3" - integrity sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw== - -"@biomejs/cli-darwin-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.0.0.tgz#49a7e064bad53e095d8a152b072adffcdeb4fb8e" - integrity sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw== - -"@biomejs/cli-linux-arm64-musl@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0.tgz#bfde27de8262a20e57e153f3807f47a01ccaeab3" - integrity sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA== - -"@biomejs/cli-linux-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.0.0.tgz#c2404b3869c03a6fa5a8b979755bc6dfd5a5ec47" - integrity sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw== - -"@biomejs/cli-linux-x64-musl@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0.tgz#8ab214ac7e21a2af29435439145888c50f2bdd2f" - integrity sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA== - -"@biomejs/cli-linux-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.0.0.tgz#cbd172ead9e5bba8cd590d06e6e548445cf7ab2a" - integrity sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg== - -"@biomejs/cli-win32-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.0.0.tgz#4677f4e034b3f4906e448b704f3314b38062a111" - integrity sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw== - -"@biomejs/cli-win32-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.0.0.tgz#f460a6950235c8f4bbd4cc405b210fec5cdb8ac9" - integrity sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg== - -"@ethersproject/abi@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.8.0.tgz#e79bb51940ac35fe6f3262d7fe2cdb25ad5f07d9" - integrity sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== - dependencies: - "@ethersproject/address" "^5.8.0" - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/constants" "^5.8.0" - "@ethersproject/hash" "^5.8.0" - "@ethersproject/keccak256" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - "@ethersproject/strings" "^5.8.0" - -"@ethersproject/abstract-provider@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz#7581f9be601afa1d02b95d26b9d9840926a35b0c" - integrity sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== - dependencies: - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/networks" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - "@ethersproject/transactions" "^5.8.0" - "@ethersproject/web" "^5.8.0" - -"@ethersproject/abstract-signer@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz#8d7417e95e4094c1797a9762e6789c7356db0754" - integrity sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== - dependencies: - "@ethersproject/abstract-provider" "^5.8.0" - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - -"@ethersproject/address@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.8.0.tgz#3007a2c352eee566ad745dca1dbbebdb50a6a983" - integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== - dependencies: - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/keccak256" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/rlp" "^5.8.0" - -"@ethersproject/base64@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.8.0.tgz#61c669c648f6e6aad002c228465d52ac93ee83eb" - integrity sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== - dependencies: - "@ethersproject/bytes" "^5.8.0" - -"@ethersproject/bignumber@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.8.0.tgz#c381d178f9eeb370923d389284efa19f69efa5d7" - integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== - dependencies: - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - bn.js "^5.2.1" - -"@ethersproject/bytes@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.8.0.tgz#9074820e1cac7507a34372cadeb035461463be34" - integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== - dependencies: - "@ethersproject/logger" "^5.8.0" - -"@ethersproject/constants@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.8.0.tgz#12f31c2f4317b113a4c19de94e50933648c90704" - integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== - dependencies: - "@ethersproject/bignumber" "^5.8.0" - -"@ethersproject/hash@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.8.0.tgz#b8893d4629b7f8462a90102572f8cd65a0192b4c" - integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== - dependencies: - "@ethersproject/abstract-signer" "^5.8.0" - "@ethersproject/address" "^5.8.0" - "@ethersproject/base64" "^5.8.0" - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/keccak256" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - "@ethersproject/strings" "^5.8.0" - -"@ethersproject/keccak256@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.8.0.tgz#d2123a379567faf2d75d2aaea074ffd4df349e6a" - integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== - dependencies: - "@ethersproject/bytes" "^5.8.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.8.0.tgz#f0232968a4f87d29623a0481690a2732662713d6" - integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== - -"@ethersproject/networks@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.8.0.tgz#8b4517a3139380cba9fb00b63ffad0a979671fde" - integrity sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== - dependencies: - "@ethersproject/logger" "^5.8.0" - -"@ethersproject/properties@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.8.0.tgz#405a8affb6311a49a91dabd96aeeae24f477020e" - integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== - dependencies: - "@ethersproject/logger" "^5.8.0" - -"@ethersproject/rlp@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.8.0.tgz#5a0d49f61bc53e051532a5179472779141451de5" - integrity sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== - dependencies: - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - -"@ethersproject/signing-key@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.8.0.tgz#9797e02c717b68239c6349394ea85febf8893119" - integrity sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== - dependencies: - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - bn.js "^5.2.1" - elliptic "6.6.1" - hash.js "1.1.7" - -"@ethersproject/strings@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.8.0.tgz#ad79fafbf0bd272d9765603215ac74fd7953908f" - integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== - dependencies: - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/constants" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - -"@ethersproject/transactions@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.8.0.tgz#1e518822403abc99def5a043d1c6f6fe0007e46b" - integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== - dependencies: - "@ethersproject/address" "^5.8.0" - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/constants" "^5.8.0" - "@ethersproject/keccak256" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - "@ethersproject/rlp" "^5.8.0" - "@ethersproject/signing-key" "^5.8.0" - -"@ethersproject/web@^5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.8.0.tgz#3e54badc0013b7a801463a7008a87988efce8a37" - integrity sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== - dependencies: - "@ethersproject/base64" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/logger" "^5.8.0" - "@ethersproject/properties" "^5.8.0" - "@ethersproject/strings" "^5.8.0" - -"@graphql-typed-document-node/core@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== - -"@grpc/grpc-js@^1.12.6": - version "1.13.4" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.4.tgz#922fbc496e229c5fa66802d2369bf181c1df1c5a" - integrity sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg== - dependencies: - "@grpc/proto-loader" "^0.7.13" - "@js-sdsl/ordered-map" "^4.4.2" - -"@grpc/proto-loader@^0.7.13": - version "0.7.15" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" - integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== - dependencies: - lodash.camelcase "^4.3.0" - long "^5.0.0" - protobufjs "^7.2.5" - yargs "^17.7.2" - -"@hashgraph/cryptography@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@hashgraph/cryptography/-/cryptography-1.9.0.tgz#eda84887e5909a850b013575d87f8bdb9e9393f9" - integrity sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg== - dependencies: - "@noble/curves" "^1.8.1" - asn1js "^3.0.6" - bignumber.js "^9.1.1" - bn.js "^5.2.1" - buffer "^6.0.3" - crypto-js "^4.2.0" - forge-light "1.1.4" - js-base64 "^3.7.7" - react-native-get-random-values "^1.11.0" - spark-md5 "^3.0.2" - tweetnacl "^1.0.3" - utf8 "^3.0.0" - -"@hashgraph/proto@2.20.0": - version "2.20.0" - resolved "https://registry.yarnpkg.com/@hashgraph/proto/-/proto-2.20.0.tgz#4d1ef2c46b7cea8d0426163d5b145d20f7a627a8" - integrity sha512-XGIHRE9jr4wnnmCG8JeUD/nyeCiiYoUt35oRJz0QdCUwJYtbEsR6tPQxO90PxJJVDI5smT1c5i0f9wRRtFDhIA== - dependencies: - long "^5.2.3" - protobufjs "7.2.5" - -"@hashgraph/sdk@^2.70.0": - version "2.70.0" - resolved "https://registry.yarnpkg.com/@hashgraph/sdk/-/sdk-2.70.0.tgz#2dd8457e220f1babba0ccf91dc4085f275a2a7b6" - integrity sha512-naml5lWgewD3Dh8z0K7NRuKpbOpDaxpxwcLjtB9RFVmATMDU3IShSzxy24k5tUgY/0ZE7XXfCKgIpdT7TxGKqQ== - dependencies: - "@ethersproject/abi" "^5.8.0" - "@ethersproject/bignumber" "^5.8.0" - "@ethersproject/bytes" "^5.8.0" - "@ethersproject/rlp" "^5.8.0" - "@grpc/grpc-js" "^1.12.6" - "@hashgraph/cryptography" "1.9.0" - "@hashgraph/proto" "2.20.0" - bignumber.js "^9.1.1" - bn.js "^5.1.1" - crypto-js "^4.2.0" - js-base64 "^3.7.4" - long "^5.3.1" - pino "^9.6.0" - pino-pretty "^13.0.0" - protobufjs "7.2.5" - rfc4648 "^1.5.3" - utf8 "^3.0.0" - -"@js-sdsl/ordered-map@^4.4.2": - version "4.4.2" - resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" - integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== - -"@noble/curves@^1.8.1": - version "1.9.7" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" - integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== - dependencies: - "@noble/hashes" "1.8.0" - -"@noble/hashes@1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" - integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - -"@sinclair/typebox@^0.34.33": - version "0.34.39" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.39.tgz#41db8ed5ff33fdd47cb34dab250c0eaea7a1a5be" - integrity sha512-keEoFsevmLwAedzacnTVmra66GViRH3fhWO1M+nZ8rUgpPJyN4mcvqlGr3QMrQXx4L8KNwW0q9/BeHSEoO4teg== - -"@sinclair/typemap@^0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@sinclair/typemap/-/typemap-0.10.1.tgz#5d1e5267ec535275c8adce21ace364f5d9c86ff7" - integrity sha512-UXR0fhu/n3c9B6lB+SLI5t1eVpt9i9CdDrp2TajRe3LbKiUhCTZN2kSfJhjPnpc3I59jMRIhgew7+0HlMi08mg== - -"@types/bun@^1.2.17": - version "1.2.20" - resolved "https://registry.yarnpkg.com/@types/bun/-/bun-1.2.20.tgz#2b7339f063a5a27a4ef10fd7d0f21095b578eee5" - integrity sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA== - dependencies: - bun-types "1.2.20" - -"@types/node@*", "@types/node@>=13.7.0": - version "24.3.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-24.3.0.tgz#89b09f45cb9a8ee69466f18ee5864e4c3eb84dec" - integrity sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow== - dependencies: - undici-types "~7.10.0" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -"aproba@^1.0.3 || ^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1" - integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew== - -are-we-there-yet@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" - integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -asn1js@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.6.tgz#53e002ebe00c5f7fd77c1c047c3557d7c04dce25" - integrity sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA== - dependencies: - pvtsutils "^1.3.6" - pvutils "^1.1.3" - tslib "^2.8.1" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -axios@^0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" - integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== - dependencies: - follow-redirects "^1.14.4" - -axios@^1.6.5: - version "1.11.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6" - integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.4" - proxy-from-env "^1.1.0" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bignumber.js@^9.1.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" - integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bl@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bn.js@^4.11.9: - version "4.12.2" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" - integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== - -bn.js@^5.1.1, bn.js@^5.2.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" - integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bun-types@1.2.20: - version "1.2.20" - resolved "https://registry.yarnpkg.com/bun-types/-/bun-types-1.2.20.tgz#7ff3a05b2183fbe33d51c76ac99ae83aaf882988" - integrity sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA== - dependencies: - "@types/node" "*" - -call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" - integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -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" - -cmake-js@^7.2.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.3.1.tgz#ed661eebd22a56d4743d7d2106a56fe50aa4355c" - integrity sha512-aJtHDrTFl8qovjSSqXT9aC2jdGfmP8JQsPtjdLAXFfH1BF4/ImZ27Jx0R61TFg8Apc3pl6e2yBKMveAeRXx2Rw== - dependencies: - axios "^1.6.5" - debug "^4" - fs-extra "^11.2.0" - memory-stream "^1.0.0" - node-api-headers "^1.1.0" - npmlog "^6.0.2" - rc "^1.2.7" - semver "^7.5.4" - tar "^6.2.0" - url-join "^4.0.1" - which "^2.0.2" - yargs "^17.7.2" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -colorette@^2.0.7: - version "2.0.20" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.9.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - -cookie@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" - integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== - -crypto-js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" - integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== - -date-format@^4.0.14: - version "4.0.14" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" - integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== - -dateformat@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" - integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== - -debug@^4, debug@^4.3.3, debug@^4.3.4: - version "4.4.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" - integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== - dependencies: - ms "^2.1.3" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - -dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - -elliptic@6.6.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" - integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -elysia@1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/elysia/-/elysia-1.3.8.tgz#66bd20f578ce936b0b29180cdb6afc2ef186ad3d" - integrity sha512-kxYFhegJbUEf5otzmisEvGt3R7d/dPBNVERO2nHo0kFqKBHyj5slArc90mSRKLfi1vamMtPcz67rL6Zeg5F2yg== - dependencies: - cookie "^1.0.2" - exact-mirror "0.1.3" - fast-decode-uri-component "^1.0.1" - optionalDependencies: - "@sinclair/typebox" "^0.34.33" - openapi-types "^12.1.3" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.5" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" - integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== - dependencies: - once "^1.4.0" - -es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" - integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - has-tostringtag "^1.0.2" - hasown "^2.0.2" - -escalade@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -exact-mirror@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/exact-mirror/-/exact-mirror-0.1.3.tgz#62fef6056a9bd808bca01ecd38f342f92ea9bb08" - integrity sha512-yI62LpSby0ItzPJF05C4DRycVAoknRiCIDOLOCCs9zaEKylOXQtOFM3flX54S44swpRz584vk3P70yWQodsLlg== - -execspawn@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/execspawn/-/execspawn-1.0.1.tgz#8286f9dde7cecde7905fbdc04e24f368f23f8da6" - integrity sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg== - dependencies: - util-extend "^1.0.1" - -fast-base64-decode@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" - integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== - -fast-copy@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.2.tgz#59c68f59ccbcac82050ba992e0d5c389097c9d35" - integrity sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== - -fast-decode-uri-component@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" - integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== - -fast-redact@^3.1.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" - integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== - -fast-safe-stringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -flatted@^3.2.7: - version "3.3.3" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" - integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== - -follow-redirects@^1.14.4, follow-redirects@^1.15.6: - version "1.15.11" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" - integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== - -forge-light@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/forge-light/-/forge-light-1.1.4.tgz#765da0d54e19c6644f37e7e5b873e1305ce78d1e" - integrity sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g== - -form-data@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" - integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - es-set-tostringtag "^2.1.0" - hasown "^2.0.2" - mime-types "^2.1.12" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-extra@^11.2.0: - version "11.3.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.1.tgz#ba7a1f97a85f94c6db2e52ff69570db3671d5a74" - integrity sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -gauge@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" - integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^3.0.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" - -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-intrinsic@^1.2.6: - version "1.3.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" - integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== - dependencies: - call-bind-apply-helpers "^1.0.2" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.1.1" - function-bind "^1.1.2" - get-proto "^1.0.1" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - -get-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -"gradido-blockchain-js@git+https://github.com/gradido/gradido-blockchain-js": - version "0.0.1" - resolved "git+https://github.com/gradido/gradido-blockchain-js#9a5f392267bd313399b851e4dc6b5af7b959be3e" - dependencies: - bindings "^1.5.0" - nan "^2.20.0" - node-addon-api "^7.1.1" - node-gyp-build "^4.8.1" - prebuildify "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" - -graphql-request@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-7.2.0.tgz#af4aa25f27a087dd4fc93a4ff54a0f59c4487269" - integrity sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A== - dependencies: - "@graphql-typed-document-node/core" "^3.2.0" - -has-symbols@^1.0.3, has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== - -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -help-me@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" - integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -jose@^5.2.2: - version "5.10.0" - resolved "https://registry.yarnpkg.com/jose/-/jose-5.10.0.tgz#c37346a099d6467c401351a9a0c2161e0f52c4be" - integrity sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg== - -joycon@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - -js-base64@^3.7.4, js-base64@^3.7.7: - version "3.7.8" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.8.tgz#af44496bc09fa178ed9c4adf67eb2b46f5c6d2a4" - integrity sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow== - -js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" - integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonrpc-ts-client@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/jsonrpc-ts-client/-/jsonrpc-ts-client-0.2.3.tgz#ec50c413d84041564e6c8a4003ab4bb360d5cfcc" - integrity sha512-9uYpKrZKN3/3+9MYA/0vdhl9/esn59u6I9Qj6ohczxKwJ+e7DD4prf3i2nSdAl0Wlw5gBHZOL3wajSa1uiE16g== - dependencies: - axios "^0.24.0" - debug "^4.3.3" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - -log4js@^6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" - integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== - dependencies: - date-format "^4.0.14" - debug "^4.3.4" - flatted "^3.2.7" - rfdc "^1.3.0" - streamroller "^3.1.5" - -long@^5.0.0, long@^5.2.3, long@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" - integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - -memory-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/memory-stream/-/memory-stream-1.0.0.tgz#481dfd259ccdf57b03ec2c9632960044180e73c2" - integrity sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww== - dependencies: - readable-stream "^3.4.0" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nan@^2.20.0: - version "2.23.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.0.tgz#24aa4ddffcc37613a2d2935b97683c1ec96093c6" - integrity sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ== - -node-abi@^3.3.0: - version "3.75.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.75.0.tgz#2f929a91a90a0d02b325c43731314802357ed764" - integrity sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg== - dependencies: - semver "^7.3.5" - -node-addon-api@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" - integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== - -node-api-headers@^1.1.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.5.0.tgz#73a0bab642c77e39b815b6d24ad4c6b56f695912" - integrity sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ== - -node-gyp-build@^4.8.1: - version "4.8.4" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" - integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== - -npm-path@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" - integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== - dependencies: - which "^1.2.10" - -npm-run-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" - integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== - dependencies: - path-key "^3.0.0" - -npm-which@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" - integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== - dependencies: - commander "^2.9.0" - npm-path "^2.0.2" - which "^1.2.10" - -npmlog@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== - dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" - -on-exit-leak-free@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" - integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== - -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -openapi-types@^12.1.3: - version "12.1.3" - resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" - integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== - -path-key@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -pino-abstract-transport@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz#de241578406ac7b8a33ce0d77ae6e8a0b3b68a60" - integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw== - dependencies: - split2 "^4.0.0" - -pino-pretty@^13.0.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-13.1.1.tgz#70130b9ff3737c8757f53e42d69e9f96835142b8" - integrity sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA== - dependencies: - colorette "^2.0.7" - dateformat "^4.6.3" - fast-copy "^3.0.2" - fast-safe-stringify "^2.1.1" - help-me "^5.0.0" - joycon "^3.1.1" - minimist "^1.2.6" - on-exit-leak-free "^2.1.0" - pino-abstract-transport "^2.0.0" - pump "^3.0.0" - secure-json-parse "^4.0.0" - sonic-boom "^4.0.1" - strip-json-comments "^5.0.2" - -pino-std-serializers@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" - integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== - -pino@^9.6.0: - version "9.9.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-9.9.0.tgz#0d2667ab4a54b561a4434a321ec595f305ab9cd1" - integrity sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.1.1" - on-exit-leak-free "^2.1.0" - pino-abstract-transport "^2.0.0" - pino-std-serializers "^7.0.0" - process-warning "^5.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.2.0" - safe-stable-stringify "^2.3.1" - sonic-boom "^4.0.1" - thread-stream "^3.0.0" - -"prebuildify@git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2": - version "6.0.1" - resolved "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" - dependencies: - cmake-js "^7.2.1" - execspawn "^1.0.1" - minimist "^1.2.5" - mkdirp-classic "^0.5.3" - node-abi "^3.3.0" - npm-run-path "^3.1.0" - npm-which "^3.0.1" - pump "^3.0.0" - tar-fs "^2.1.0" - -process-warning@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" - integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== - -protobufjs@7.2.5: - version "7.2.5" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d" - integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - -protobufjs@^7.2.5: - version "7.5.4" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" - integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - -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.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" - integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pvtsutils@^1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" - integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== - dependencies: - tslib "^2.8.1" - -pvutils@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" - integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== - -quick-format-unescaped@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" - integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -react-native-get-random-values@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz#1ca70d1271f4b08af92958803b89dccbda78728d" - integrity sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ== - dependencies: - fast-base64-decode "^1.0.0" - -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -real-require@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" - integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== - -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== - -rfc4648@^1.5.3: - version "1.5.4" - resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.4.tgz#1174c0afba72423a0b70c386ecfeb80aa61b05ca" - integrity sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg== - -rfdc@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" - integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== - -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-stable-stringify@^2.3.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" - integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== - -secure-json-parse@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-4.0.0.tgz#2ee1b7581be38ab348bab5a3e49280ba80a89c85" - integrity sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA== - -semver@^7.3.5, semver@^7.5.4: - version "7.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" - integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sonic-boom@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d" - integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww== - dependencies: - atomic-sleep "^1.0.0" - -spark-md5@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" - integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== - -split2@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== - -streamroller@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" - integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== - dependencies: - date-format "^4.0.14" - debug "^4.3.4" - fs-extra "^8.1.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, 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== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" - integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -tar-fs@^2.1.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" - integrity sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" - integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^5.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -thread-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-3.1.0.tgz#4b2ef252a7c215064507d4ef70c05a5e2d34c4f1" - integrity sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== - dependencies: - real-require "^0.2.0" - -tslib@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -typescript@^5.8.3: - version "5.9.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" - integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== - -undici-types@~7.10.0: - version "7.10.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350" - integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag== - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -url-join@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" - integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== - -utf8@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== - -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -util-extend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - integrity sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA== - -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== - -valibot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/valibot/-/valibot-1.1.0.tgz#873bb1af9e1577391690307bfe0520bd1360ec2d" - integrity sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw== - -which@^1.2.10: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.2: - 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" - -wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -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.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - 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" From c06f82bf2947131a73a9caec9a260535fe6074c5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 3 Sep 2025 15:02:36 +0200 Subject: [PATCH 029/226] auto create and update hiero topic --- .../src/client/backend/BackendClient.ts | 23 ++++++++++++++----- .../src/client/backend/community.schema.ts | 13 ++++++++++- dlt-connector/src/client/hiero/HieroClient.ts | 7 +++--- .../src/client/hiero/output.schema.ts | 19 ++------------- dlt-connector/src/config/const.ts | 2 ++ dlt-connector/src/index.ts | 22 +++++++++++++++--- 6 files changed, 56 insertions(+), 30 deletions(-) diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 5e2bec24f..8545ec1f4 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -2,10 +2,16 @@ import { GraphQLClient } from 'graphql-request' import { SignJWT } from 'jose' import { CONFIG } from '../../config' -import { communitySchema, type Community, homeCommunityGraphqlQuery } from './community.schema' +import { + communitySchema, + type Community, + homeCommunityGraphqlQuery, + setHomeCommunityTopicId +} from './community.schema' import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import * as v from 'valibot' +import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -53,9 +59,7 @@ export class BackendClient { public async getHomeCommunityDraft(): Promise { this.logger.info('check home community on backend') const { data, errors } = await this.client.rawRequest<{ homeCommunity: Community }>( - homeCommunityGraphqlQuery, - {}, // empty variables - await this.getRequestHeader(), + homeCommunityGraphqlQuery, {}, await this.getRequestHeader(), ) if (errors) { throw errors[0] @@ -63,8 +67,15 @@ export class BackendClient { return v.parse(communitySchema, data.homeCommunity) } - public async setHomeCommunityTopicId(topicId: HieroId) { - + public async setHomeCommunityTopicId(uuid: Uuidv4, hieroTopicId: HieroId): Promise { + this.logger.info('update home community on backend') + const { data, errors } = await this.client.rawRequest<{ updateHomeCommunity: Community }>( + setHomeCommunityTopicId, { uuid, hieroTopicId }, await this.getRequestHeader(), + ) + if (errors) { + throw errors[0] + } + return v.parse(communitySchema, data.updateHomeCommunity) } private async getRequestHeader(): Promise<{ diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts index 4c99f10b4..0222322a4 100644 --- a/dlt-connector/src/client/backend/community.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -12,7 +12,7 @@ import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' */ export const communitySchema = v.object({ uuid: uuidv4Schema, - topicId: v.optional(hieroIdSchema, ''), + topicId: v.nullish(hieroIdSchema), foreign: v.boolean('expect boolean type'), createdAt: dateSchema, }) @@ -31,3 +31,14 @@ export const homeCommunityGraphqlQuery = gql` } } ` + +export const setHomeCommunityTopicId = gql` + mutation ($uuid: string, $hieroTopicId: string){ + updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { + uuid + topicId + foreign + creationDate + } + } +` diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 10fa23592..a058f1c72 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -85,9 +85,9 @@ export class HieroClient { return balance } - public async getTopicInfo(topicId: HieroTopicId): Promise { + public async getTopicInfo(topicId: HieroId): Promise { const info = await new TopicInfoQuery() - .setTopicId(new TopicId(topicId.getShardNum(), topicId.getRealmNum(), topicId.getTopicNum())) + .setTopicId(TopicId.fromString(topicId)) .execute(this.client) this.logger.debug(JSON.stringify(info, null, 2)) return parse(topicInfoSchema, { @@ -108,9 +108,10 @@ export class HieroClient { return parse(hieroIdSchema, createReceipt.topicId?.toString()) } - public async updateTopic(): Promise { + public async updateTopic(topicId: HieroId): Promise { let transaction = new TopicUpdateTransaction() transaction.setExpirationTime(new Date(new Date().getTime() + MIN_AUTORENEW_PERIOD * 1000)) + transaction.setTopicId(TopicId.fromString(topicId)) transaction = await transaction.freezeWithSigner(this.wallet) transaction = await transaction.signWithSigner(this.wallet) const updateResponse = await transaction.executeWithSigner(this.wallet) diff --git a/dlt-connector/src/client/hiero/output.schema.ts b/dlt-connector/src/client/hiero/output.schema.ts index 3f0218010..da1864aae 100644 --- a/dlt-connector/src/client/hiero/output.schema.ts +++ b/dlt-connector/src/client/hiero/output.schema.ts @@ -1,5 +1,6 @@ import * as v from 'valibot' import { hieroIdSchema } from '../../schemas/typeGuard.schema' +import { dateSchema } from '../../schemas/typeConverter.schema' // schema definitions for exporting data from hiero request as json back to caller /*export const dateStringSchema = v.pipe( @@ -7,28 +8,12 @@ import { hieroIdSchema } from '../../schemas/typeGuard.schema' v.transform(in: string | Date) )*/ -export const dateStringSchema = v.pipe( - v.union([v.string('expect valid date string'), v.instance(Date, 'expect Date object')]), - v.transform((input) => { - let date: Date - if (input instanceof Date) { - date = input - } else { - date = new Date(input) - } - if (isNaN(date.getTime())) { - throw new Error('invalid date') - } - return date.toISOString() - }), -) - export const positiveNumberSchema = v.pipe(v.number(), v.minValue(0)) export const topicInfoSchema = v.object({ topicId: hieroIdSchema, sequenceNumber: positiveNumberSchema, - expirationTime: dateStringSchema, + expirationTime: dateSchema, autoRenewPeriod: v.optional(positiveNumberSchema, 0), autoRenewAccountId: v.optional(hieroIdSchema, '0.0.0'), }) diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index 14b5cf215..91dd84707 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -1 +1,3 @@ export const LOG4JS_BASE_CATEGORY = 'dlt' +// 7 days +export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 \ No newline at end of file diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 5ea9faa2e..de0b07729 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -12,6 +12,7 @@ import { KeyPairCacheManager } from './KeyPairCacheManager' import { keyGenerationSeedSchema } from './schemas/base.schema' import { isPortOpenRetry } from './utils/network' import { appRoutes } from './server' +import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' async function main() { // configure log4js @@ -36,13 +37,28 @@ async function main() { if (!backend) { throw new Error('cannot create backend client') } + const hieroClient = HieroClient.getInstance() + if (!hieroClient) { + throw new Error('cannot create hiero client') + } // wait for backend server await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) - const homeCommunity = await backend.getHomeCommunityDraft() + let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.topicId) { - const topicId = await HieroClient.getInstance().createTopic() - + const topicId = await hieroClient.createTopic() + homeCommunity = await backend.setHomeCommunityTopicId(homeCommunity.uuid, topicId) + } else { + // if topic exist, check if we need to update it + let topicInfo = await hieroClient.getTopicInfo(homeCommunity.topicId) + if (topicInfo.expirationTime.getTime() - new Date().getTime() < MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE) { + await hieroClient.updateTopic(homeCommunity.topicId) + topicInfo = await hieroClient.getTopicInfo(homeCommunity.topicId) + logger.info('updated topic info, new expiration time: %s', topicInfo.expirationTime.toLocaleDateString()) + } + } + if (!homeCommunity.topicId) { + throw new Error('still no topic id, after creating topic and update community in backend.') } KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.topicId) logger.info('home community topic: %s', homeCommunity.topicId) From 18879cf207937feb346daacde958ab1929165928 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 6 Sep 2025 12:53:51 +0200 Subject: [PATCH 030/226] change for hiero --- .../apis/dltConnector/DltConnectorClient.ts | 4 +- .../AbstractTransactionToDlt.role.ts | 15 +- .../TransactionLinkDeleteToDlt.role.ts | 3 +- .../transactionToDlt/TransactionToDlt.role.ts | 3 +- .../transactionToDlt/UserToDlt.role.ts | 3 +- .../transactionToDlt.context.ts | 16 +- .../sendTransactionsToDltConnector.ts | 11 +- backend/src/auth/DLT_CONNECTOR_RIGHTS.ts | 2 +- dlt-connector/bun.lock | 34 +- dlt-connector/log4js-config.json | 2 +- .../client/GradidoNode/GradidoNodeClient.ts | 251 +++++++++++++ dlt-connector/src/client/GradidoNode/api.ts | 182 ---------- .../client/GradidoNode/input.schema.test.ts | 60 ++++ .../src/client/GradidoNode/input.schema.ts | 4 +- .../src/client/GradidoNode/jsonrpc.ts | 60 ---- .../src/client/backend/BackendClient.ts | 33 +- .../client/backend/community.schema.test.ts | 11 +- .../src/client/backend/community.schema.ts | 16 +- dlt-connector/src/client/hiero/HieroClient.ts | 20 +- .../src/client/hiero/output.schema.ts | 15 +- dlt-connector/src/config/const.ts | 2 +- dlt-connector/src/config/index.ts | 71 +--- dlt-connector/src/config/schema.ts | 91 ++++- .../src/data/KeyPairIdentifier.logic.ts | 4 +- dlt-connector/src/errors.ts | 14 + dlt-connector/src/index.ts | 122 ++++--- .../keyPairCalculation/AccountKeyPair.role.ts | 10 +- .../ForeignCommunityKeyPair.role.ts | 13 +- .../HomeCommunityKeyPair.role.ts | 13 +- .../RemoteAccountKeyPair.role.ts | 5 +- .../keyPairCalculation/UserKeyPair.role.ts | 15 +- .../AbstractTransaction.role.ts | 0 .../CommunityRootTransaction.role.ts | 23 +- .../CreationTransaction.role.ts | 0 .../DeferredTransferTransaction.role.ts | 0 .../RedeemDeferredTransferTransaction.role.ts | 4 +- .../RegisterAddressTransaction.role.ts | 4 +- .../SendToHiero.context.ts} | 39 +- .../TransferTransaction.role.ts | 12 +- .../src/schemas/transaction.schema.test.ts | 333 ++++++++---------- .../src/schemas/transaction.schema.ts | 14 + .../src/schemas/typeConverter.schema.test.ts | 4 +- .../src/schemas/typeConverter.schema.ts | 3 +- dlt-connector/src/server/index.ts | 65 ++-- dlt-connector/src/utils/typeConverter.ts | 28 +- 45 files changed, 865 insertions(+), 769 deletions(-) create mode 100644 dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts delete mode 100644 dlt-connector/src/client/GradidoNode/api.ts create mode 100644 dlt-connector/src/client/GradidoNode/input.schema.test.ts delete mode 100644 dlt-connector/src/client/GradidoNode/jsonrpc.ts rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/AbstractTransaction.role.ts (100%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/CommunityRootTransaction.role.ts (68%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/CreationTransaction.role.ts (100%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/DeferredTransferTransaction.role.ts (100%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/RedeemDeferredTransferTransaction.role.ts (95%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/RegisterAddressTransaction.role.ts (94%) rename dlt-connector/src/interactions/{sendToIota/SendToIota.context.ts => sendToHiero/SendToHiero.context.ts} (83%) rename dlt-connector/src/interactions/{sendToIota => sendToHiero}/TransferTransaction.role.ts (90%) diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 2533e7509..4fef742ed 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -1,11 +1,11 @@ -import { GraphQLClient, gql } from 'graphql-request' - import { CONFIG } from '@/config' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLogger } from 'log4js' import { TransactionDraft } from './model/TransactionDraft' import { TransactionResult } from './model/TransactionResult' +import { GraphQLClient } from 'graphql-request' +import { gql } from 'graphql-request' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector`) diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts index ac77f4195..5e756fb7d 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -1,10 +1,10 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from '@dbTools/typeorm' -import { DltTransaction } from '@entity/DltTransaction' +import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from 'typeorm' +import { DltTransaction } from 'database' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' - -import { backendLogger as logger } from '@/server/logger' +import { getLogger, Logger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' export abstract class AbstractTransactionToDltRole { protected self: T | null @@ -14,6 +14,9 @@ export abstract class AbstractTransactionToDltRole { public abstract getTimestamp(): number public abstract convertToGraphqlInput(): TransactionDraft + + public constructor(protected logger: Logger) {} + public getEntity(): T | null { return this.self } @@ -25,11 +28,11 @@ export abstract class AbstractTransactionToDltRole { this.setJoinIdAndType(dltTransaction) await DltTransaction.save(dltTransaction) if (dltTransaction.error) { - logger.error( + this.logger.error( `Store dltTransaction with error: id=${dltTransaction.id}, error=${dltTransaction.error}`, ) } else { - logger.info( + this.logger.info( `Store dltTransaction: messageId=${dltTransaction.messageId}, id=${dltTransaction.id}`, ) } diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts index b761b71c6..b8eaa633a 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts @@ -1,5 +1,4 @@ -import { DltTransaction } from '@entity/DltTransaction' -import { TransactionLink } from '@entity/TransactionLink' +import { DltTransaction, TransactionLink } from 'database' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts index de96d38cc..9e078e874 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts @@ -1,5 +1,4 @@ -import { DltTransaction } from '@entity/DltTransaction' -import { Transaction } from '@entity/Transaction' +import { DltTransaction, Transaction } from 'database' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts index 6319880fe..94b95ccdd 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts @@ -1,5 +1,4 @@ -import { DltTransaction } from '@entity/DltTransaction' -import { User } from '@entity/User' +import { DltTransaction, User } from 'database' import { AccountType } from '@dltConnector/enum/AccountType' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts index febb3b5ae..b03bd5300 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -1,16 +1,15 @@ -import { Transaction } from '@entity/Transaction' -import { TransactionLink } from '@entity/TransactionLink' -import { User } from '@entity/User' +import { Transaction, TransactionLink, User } from 'database' import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' -import { backendLogger as logger } from '@/server/logger' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role' import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' import { TransactionToDltRole } from './TransactionToDlt.role' import { UserToDltRole } from './UserToDlt.role' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' /** * @DCI-Context @@ -20,12 +19,13 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis async function findNextPendingTransaction(): Promise< AbstractTransactionToDltRole > { + const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/interaction/transactionToDlt`) // collect each oldest not sended entity from db and choose oldest const results = await Promise.all([ - new TransactionToDltRole().initWithLast(), - new UserToDltRole().initWithLast(), - new TransactionLinkToDltRole().initWithLast(), - new TransactionLinkDeleteToDltRole().initWithLast(), + new TransactionToDltRole(logger).initWithLast(), + new UserToDltRole(logger).initWithLast(), + new TransactionLinkToDltRole(logger).initWithLast(), + new TransactionLinkDeleteToDltRole(logger).initWithLast(), ]) // sort array to get oldest at first place diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts index 73dd6cbab..3b0bfbc27 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -1,7 +1,6 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { CONFIG } from '@/config' -import { backendLogger as logger } from '@/server/logger' -import { TypeORMError } from '@dbTools/typeorm' +import { TypeORMError } from 'typeorm' // eslint-disable-next-line import/named, n/no-extraneous-import import { FetchError } from 'node-fetch' @@ -14,6 +13,10 @@ import { } from '@/util/InterruptiveSleepManager' import { transactionToDlt } from './interaction/transactionToDlt/transactionToDlt.context' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/sendTransactionsToDltConnector`) let isLoopRunning = true @@ -25,11 +28,11 @@ export async function sendTransactionsToDltConnector(): Promise { const dltConnector = DltConnectorClient.getInstance() if (!dltConnector) { - logger.info('Sending to DltConnector currently not configured...') + logger.info('currently not configured...') isLoopRunning = false return } - logger.info('Starting sendTransactionsToDltConnector task') + logger.info('task started') // define outside of loop for reuse and reducing gb collection // const queries = getFindNextPendingTransactionQueries() diff --git a/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts b/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts index 399b7c2d4..e7cdc3806 100644 --- a/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts +++ b/backend/src/auth/DLT_CONNECTOR_RIGHTS.ts @@ -1,3 +1,3 @@ import { RIGHTS } from './RIGHTS' -export const DLT_CONNECTOR_RIGHTS = [RIGHTS.COMMUNITY_BY_IDENTIFIER, RIGHTS.HOME_COMMUNITY] +export const DLT_CONNECTOR_RIGHTS = [RIGHTS.COMMUNITY_BY_IDENTIFIER, RIGHTS.HOME_COMMUNITY, RIGHTS.COMMUNITY_UPDATE] diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index b300ad89a..05852adda 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -25,13 +25,11 @@ }, }, "packages": { - "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], + "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="], - "@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="], + "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], @@ -51,9 +49,9 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="], + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], + "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="], "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], @@ -85,15 +83,15 @@ "@babel/plugin-syntax-top-level-await": ["@babel/plugin-syntax-top-level-await@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw=="], - "@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], - "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], + "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], - "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], + "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], @@ -183,6 +181,8 @@ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], @@ -265,7 +265,7 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], - "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], + "@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="], "@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="], @@ -359,7 +359,7 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001739", "", {}, "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA=="], + "caniuse-lite": ["caniuse-lite@1.0.30001741", "", {}, "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -425,7 +425,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.213", "", {}, "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q=="], + "electron-to-chromium": ["electron-to-chromium@1.5.214", "", {}, "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -535,7 +535,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#eccade8", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-eccade8"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#f1c4bbc", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-f1c4bbc"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], @@ -729,7 +729,7 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "node-abi": ["node-abi@3.75.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg=="], + "node-abi": ["node-abi@3.77.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], @@ -739,7 +739,7 @@ "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + "node-releases": ["node-releases@2.0.20", "", {}, "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -785,7 +785,7 @@ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pino": ["pino@9.9.1", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-40SszWPOPwGhUIJ3zj0PsbMNV1bfg8nw5Qp/tP2FE2p3EuycmhDeYimKOMBAu6rtxcSw2QpjJsuK5A6v+en8Yw=="], + "pino": ["pino@9.9.4", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 6d96cd326..a6a33686b 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" }, "compress": true, "keepFileExt" : true, diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts new file mode 100644 index 000000000..69609657e --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -0,0 +1,251 @@ +import { ConfirmedTransaction } from 'gradido-blockchain-js' +import JsonRpcClient from 'jsonrpc-ts-client' +import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' +import { getLogger, Logger } from 'log4js' +import { parse } from 'valibot' +import { CONFIG } from '../../config' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { Uuidv4Hash } from '../../data/Uuidv4Hash' +import { AddressType } from '../../enum/AddressType' +import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' +import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' +import { Hex32, Hex32Input, HieroId, hex32Schema } from '../../schemas/typeGuard.schema' +import { isPortOpenRetry } from '../../utils/network' +import { + TransactionIdentifierInput, + TransactionsRangeInput, + transactionIdentifierSchema, + transactionsRangeSchema, +} from './input.schema' + +export class GradidoNodeRequestError extends Error { + private response?: JsonRpcEitherResponse + constructor(message: string, response?: JsonRpcEitherResponse) { + super(message) + this.name = 'GradidoNodeRequestError' + this.response = response + } + getResponse(): JsonRpcEitherResponse | undefined { + return this.response + } +} + +type WithTimeUsed = T & { timeUsed?: string } + +export class GradidoNodeClient { + private static instance: GradidoNodeClient + client: JsonRpcClient + logger: Logger + + private constructor() { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNodeClient`) + this.client = new JsonRpcClient({ + url: CONFIG.NODE_SERVER_URL, + }) + } + public static getInstance(): GradidoNodeClient { + if (!GradidoNodeClient.instance) { + GradidoNodeClient.instance = new GradidoNodeClient() + } + return GradidoNodeClient.instance + } + + /** + * getTransaction + * get a specific confirmed transaction from a specific community + * @param transactionIdentifier + * @returns the confirmed transaction or undefined if transaction is not found + * @throws GradidoNodeRequestError + */ + public async getTransaction( + transactionIdentifier: TransactionIdentifierInput, + ): Promise { + const parameter = { + ...parse(transactionIdentifierSchema, transactionIdentifier), + format: 'base64', + } + const response = await this.rpcCall<{ transaction: string }>('gettransaction', parameter) + if (response.isSuccess()) { + this.logger.debug('result: ', response.result.transaction) + return parse(confirmedTransactionSchema, response.result.transaction) + } + if (response.isError()) { + if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { + return undefined + } + } + throw new GradidoNodeRequestError(response.error.message, response) + } + + /** + * getLastTransaction + * get the last confirmed transaction from a specific community + * @param hieroTopic the community hiero topic id + * @returns the last confirmed transaction or undefined if blockchain for community is empty or not found + * @throws GradidoNodeRequestError + */ + + public async getLastTransaction(hieroTopic: HieroId): Promise { + const parameter = { + format: 'base64', + topic: hieroTopic, + } + const response = await this.rpcCall<{ transaction: string }>('getlasttransaction', parameter) + if (response.isSuccess()) { + return parse(confirmedTransactionSchema, response.result.transaction) + } + if (response.isError()) { + if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { + return undefined + } + } + throw new GradidoNodeRequestError(response.error.message, response) + } + + /** + * getTransactions + * get list of confirmed transactions from a specific community + * @param input fromTransactionId is the id of the first transaction to return + * @param input maxResultCount is the max number of transactions to return + * @param input topic is the community hiero topic id + * @returns list of confirmed transactions + * @throws GradidoNodeRequestError + * @example + * ``` + * const transactions = await getTransactions({ + * fromTransactionId: 1, + * maxResultCount: 100, + * topic: communityUuid, + * }) + * ``` + */ + public async getTransactions(input: TransactionsRangeInput): Promise { + const parameter = { + ...parse(transactionsRangeSchema, input), + format: 'base64', + } + const result = await this.rpcCallResolved<{ transactions: string[] }>( + 'getTransactions', + parameter, + ) + return result.transactions.map((transactionBase64) => + parse(confirmedTransactionSchema, transactionBase64), + ) + } + + /** + * getTransactionsForAccount + * get list of confirmed transactions for a specific account + * @param transactionRange the range of transactions to return + * @param pubkey the public key of the account + * @returns list of confirmed transactions + * @throws GradidoNodeRequestError + */ + public async getTransactionsForAccount( + transactionRange: TransactionsRangeInput, + pubkey: Hex32Input, + ): Promise { + const parameter = { + ...parse(transactionsRangeSchema, transactionRange), + pubkey: parse(hex32Schema, pubkey), + format: 'base64', + } + const response = await this.rpcCallResolved<{ transactions: string[] }>( + 'listtransactionsforaddress', + parameter, + ) + return response.transactions.map((transactionBase64) => + parse(confirmedTransactionSchema, transactionBase64), + ) + } + + /** + * getAddressType + * get the address type of a specific user + * can be used to check if user/account exists on blockchain + * look also for gmw, auf and deferred transfer accounts + * @param pubkey the public key of the user or account + * @param hieroTopic the community hiero topic id + * @returns the address type of the user/account, AddressType.NONE if not found + * @throws GradidoNodeRequestError + */ + + public async getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise { + const parameter = { + pubkey: parse(hex32Schema, pubkey), + topic: hieroTopic, + } + const response = await this.rpcCallResolved<{ addressType: string }>( + 'getaddresstype', + parameter, + ) + return parse(addressTypeSchema, response.addressType) + } + + /** + * findUserByNameHash + * find a user by name hash + * @param nameHash the name hash of the user + * @param hieroTopic the community hiero topic id + * @returns the public key of the user as hex32 string or undefined if user is not found + * @throws GradidoNodeRequestError + */ + public async findUserByNameHash( + nameHash: Uuidv4Hash, + hieroTopic: HieroId, + ): Promise { + const parameter = { + nameHash: nameHash.getAsHexString(), + topic: hieroTopic, + } + const response = await this.rpcCall<{ pubkey: string; timeUsed: string }>( + 'findUserByNameHash', + parameter, + ) + if (response.isSuccess()) { + this.logger.info(`call findUserByNameHash, used ${response.result.timeUsed}`) + return parse(hex32Schema, response.result.pubkey) + } + if ( + response.isError() && + response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND + ) { + this.logger.debug(`call findUserByNameHash, return with error: ${response.error.message}`) + } + return undefined + } + + // ---------------- intern helper functions ----------------------------------- + + // return result on success or throw error + protected resolveResponse( + response: JsonRpcEitherResponse, + onSuccess: (result: T) => R, + ): R { + if (response.isSuccess()) { + return onSuccess(response.result) + } else if (response.isError()) { + throw new GradidoNodeRequestError(response.error.message, response) + } + throw new GradidoNodeRequestError('no success and no error') + } + + // template rpcCall, check first if port is open before executing json rpc 2.0 request + protected async rpcCall(method: string, parameter: any): Promise> { + this.logger.debug('call %s with %s', method, parameter) + await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + return this.client.exec(method, parameter) + } + + // template rpcCall, check first if port is open before executing json rpc 2.0 request, + // throw error on failure, return result on success + protected async rpcCallResolved(method: string, parameter: any): Promise { + const response = await this.rpcCall>(method, parameter) + return this.resolveResponse(response, (result: WithTimeUsed) => { + if (result.timeUsed) { + this.logger.info(`call %s, used ${result.timeUsed}`, method) + } + return result as T + }) + } +} diff --git a/dlt-connector/src/client/GradidoNode/api.ts b/dlt-connector/src/client/GradidoNode/api.ts deleted file mode 100644 index 383f1c3f4..000000000 --- a/dlt-connector/src/client/GradidoNode/api.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { AddressType, ConfirmedTransaction } from 'gradido-blockchain-js' -import { getLogger } from 'log4js' -import * as v from 'valibot' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { Uuidv4Hash } from '../../data/Uuidv4Hash' -import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' -import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' -import { Hex32, Hex32Input, HieroId, hex32Schema } from '../../schemas/typeGuard.schema' -import { - TransactionIdentifierInput, - TransactionsRangeInput, - transactionIdentifierSchema, - transactionsRangeSchema, -} from './input.schema' -import { GradidoNodeRequestError, rpcCall, rpcCallResolved } from './jsonrpc' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) - -/** - * getTransactions - * get list of confirmed transactions from a specific community - * @param input fromTransactionId is the id of the first transaction to return - * @param input maxResultCount is the max number of transactions to return - * @param input topic is the community hiero topic id - * @returns list of confirmed transactions - * @throws GradidoNodeRequestError - * @example - * ``` - * const transactions = await getTransactions({ - * fromTransactionId: 1, - * maxResultCount: 100, - * topic: communityUuid, - * }) - * ``` - */ -async function getTransactions(input: TransactionsRangeInput): Promise { - const parameter = { ...v.parse(transactionsRangeSchema, input), format: 'base64' } - const result = await rpcCallResolved<{ transactions: string[] }>('getTransactions', parameter) - return result.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, transactionBase64), - ) -} - -/** - * getTransaction - * get a specific confirmed transaction from a specific community - * @param transactionIdentifier - * @returns the confirmed transaction or undefined if transaction is not found - * @throws GradidoNodeRequestError - */ -async function getTransaction( - transactionIdentifier: TransactionIdentifierInput, -): Promise { - const parameter = { - ...v.parse(transactionIdentifierSchema, transactionIdentifier), - format: 'base64', - } - const response = await rpcCall<{ transaction: string }>('gettransaction', parameter) - if (response.isSuccess()) { - return v.parse(confirmedTransactionSchema, response.result.transaction) - } - if (response.isError()) { - if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { - return undefined - } - } - throw new GradidoNodeRequestError(response.error.message, response) -} - -/** - * getLastTransaction - * get the last confirmed transaction from a specific community - * @param iotaTopic the community topic - * @returns the last confirmed transaction or undefined if blockchain for community is empty or not found - * @throws GradidoNodeRequestError - */ - -async function getLastTransaction( - iotaTopic: Uuidv4Hash, -): Promise { - const response = await rpcCall<{ transaction: string }>('getlasttransaction', { - format: 'base64', - topic: iotaTopic.getAsHexString(), - }) - if (response.isSuccess()) { - return v.parse(confirmedTransactionSchema, response.result.transaction) - } - if (response.isError()) { - if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { - return undefined - } - throw new GradidoNodeRequestError(response.error.message, response) - } -} - -/** - * getAddressType - * get the address type of a specific user - * can be used to check if user/account exists on blockchain - * look also for gmw, auf and deferred transfer accounts - * @param pubkey the public key of the user or account - * @param iotaTopic the community topic - * @returns the address type of the user/account or undefined - * @throws GradidoNodeRequestError - */ - -async function getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise { - const parameter = { - pubkey: v.parse(hex32Schema, pubkey), - communityId: hieroTopic, - } - const response = await rpcCallResolved<{ addressType: string }>('getaddresstype', parameter) - return v.parse(addressTypeSchema, response.addressType) -} - -/** - * findUserByNameHash - * find a user by name hash - * @param nameHash the name hash of the user - * @param iotaTopic the community topic - * @returns the public key of the user as hex32 string or undefined if user is not found - * @throws GradidoNodeRequestError - */ -async function findUserByNameHash( - nameHash: Uuidv4Hash, - hieroTopic: HieroId, -): Promise { - const parameter = { - nameHash: nameHash.getAsHexString(), - communityId: hieroTopic, - } - const response = await rpcCall<{ pubkey: string; timeUsed: string }>( - 'findUserByNameHash', - parameter, - ) - if (response.isSuccess()) { - logger.info(`call findUserByNameHash, used ${response.result.timeUsed}`) - return v.parse(hex32Schema, response.result.pubkey) - } - if ( - response.isError() && - response.error.code === GradidoNodeErrorCodes.JSON_RPC_ERROR_ADDRESS_NOT_FOUND - ) { - logger.debug(`call findUserByNameHash, return with error: ${response.error.message}`) - } - return undefined -} - -/** - * getTransactionsForAccount - * get list of confirmed transactions for a specific account - * @param transactionRange the range of transactions to return - * @param pubkey the public key of the account - * @returns list of confirmed transactions - * @throws GradidoNodeRequestError - */ -async function getTransactionsForAccount( - transactionRange: TransactionsRangeInput, - pubkey: Hex32Input, -): Promise { - const parameter = { - ...v.parse(transactionsRangeSchema, transactionRange), - pubkey: v.parse(hex32Schema, pubkey), - format: 'base64', - } - const response = await rpcCallResolved<{ transactions: string[] }>( - 'listtransactionsforaddress', - parameter, - ) - return response.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, transactionBase64), - ) -} - -export { - getTransaction, - getLastTransaction, - getTransactions, - getAddressType, - getTransactionsForAccount, - findUserByNameHash, -} diff --git a/dlt-connector/src/client/GradidoNode/input.schema.test.ts b/dlt-connector/src/client/GradidoNode/input.schema.test.ts new file mode 100644 index 000000000..1268290fc --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/input.schema.test.ts @@ -0,0 +1,60 @@ +import { beforeAll, describe, expect, it } from 'bun:test' +import { parse } from 'valibot' +import { + HieroId, + HieroTransactionId, + hieroIdSchema, + hieroTransactionIdSchema, +} from '../../schemas/typeGuard.schema' +import { transactionIdentifierSchema } from './input.schema' + +let topic: HieroId +const topicString = '0.0.261' +let hieroTransactionId: HieroTransactionId +beforeAll(() => { + topic = parse(hieroIdSchema, topicString) + hieroTransactionId = parse(hieroTransactionIdSchema, '0.0.261-1755348116-1281621') +}) + +describe('transactionIdentifierSchema ', () => { + it('valid, transaction identified by transactionNr and topic', () => { + expect( + parse(transactionIdentifierSchema, { + transactionId: 1, + topic: topicString, + }), + ).toEqual({ + transactionId: 1, + hieroTransactionId: undefined, + topic, + }) + }) + it('valid, transaction identified by hieroTransactionId and topic', () => { + expect( + parse(transactionIdentifierSchema, { + hieroTransactionId: '0.0.261-1755348116-1281621', + topic: topicString, + }), + ).toEqual({ + hieroTransactionId, + topic, + }) + }) + it('invalid, missing topic', () => { + expect(() => + parse(transactionIdentifierSchema, { + transactionId: 1, + hieroTransactionId: '0.0.261-1755348116-1281621', + }), + ).toThrowError(new Error('Invalid key: Expected "topic" but received undefined')) + }) + it('invalid, transactionNr and iotaMessageId set', () => { + expect(() => + parse(transactionIdentifierSchema, { + transactionId: 1, + hieroTransactionId: '0.0.261-1755348116-1281621', + topic, + }), + ).toThrowError(new Error('expect transactionNr or hieroTransactionId not both')) + }) +}) diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts index 218805c3f..baa075baf 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -14,7 +14,7 @@ export type TransactionsRangeInput = v.InferInput= 1')), undefined, ), @@ -23,7 +23,7 @@ export const transactionIdentifierSchema = v.pipe( }), v.custom((value: any) => { const setFieldsCount = - Number(value.transactionNr !== undefined) + Number(value.hieroTransactionId !== undefined) + Number(value.transactionId !== undefined) + Number(value.hieroTransactionId !== undefined) if (setFieldsCount !== 1) { return false } diff --git a/dlt-connector/src/client/GradidoNode/jsonrpc.ts b/dlt-connector/src/client/GradidoNode/jsonrpc.ts deleted file mode 100644 index b93ff65f0..000000000 --- a/dlt-connector/src/client/GradidoNode/jsonrpc.ts +++ /dev/null @@ -1,60 +0,0 @@ -import JsonRpcClient from 'jsonrpc-ts-client' -import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' -import { getLogger } from 'log4js' -import { CONFIG } from '../../config' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { isPortOpenRetry } from '../../utils/network' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode`) - -export const client = new JsonRpcClient({ - url: CONFIG.NODE_SERVER_URL, -}) - -export class GradidoNodeRequestError extends Error { - private response?: JsonRpcEitherResponse - constructor(message: string, response?: JsonRpcEitherResponse) { - super(message) - this.name = 'GradidoNodeRequestError' - this.response = response - } - getResponse(): JsonRpcEitherResponse | undefined { - return this.response - } -} - -// return result on success or throw error -export function resolveResponse( - response: JsonRpcEitherResponse, - onSuccess: (result: T) => R, -): R { - if (response.isSuccess()) { - return onSuccess(response.result) - } else if (response.isError()) { - throw new GradidoNodeRequestError(response.error.message, response) - } - throw new GradidoNodeRequestError('no success and no error') -} - -type WithTimeUsed = T & { timeUsed?: string } - -// template rpcCall, check first if port is open before executing json rpc 2.0 request -export async function rpcCall( - method: string, - parameter: any, -): Promise> { - logger.debug('call %s with %s', method, parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) - return client.exec(method, parameter) -} - -// template rpcCall, check first if port is open before executing json rpc 2.0 request, throw error on failure, return result on success -export async function rpcCallResolved(method: string, parameter: any): Promise { - const response = await rpcCall>(method, parameter) - return resolveResponse(response, (result: WithTimeUsed) => { - if (result.timeUsed) { - logger.info(`call %s, used ${result.timeUsed}`, method) - } - return result as T - }) -} diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 8545ec1f4..2d587a4d8 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -1,17 +1,16 @@ import { GraphQLClient } from 'graphql-request' import { SignJWT } from 'jose' - -import { CONFIG } from '../../config' -import { - communitySchema, - type Community, - homeCommunityGraphqlQuery, - setHomeCommunityTopicId -} from './community.schema' import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' import * as v from 'valibot' +import { CONFIG } from '../../config' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' +import { + type Community, + communitySchema, + homeCommunityGraphqlQuery, + setHomeCommunityTopicId, +} from './community.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts @@ -22,7 +21,7 @@ import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' export class BackendClient { private static instance: BackendClient client: GraphQLClient - logger: Logger + logger: Logger /** * The Singleton's constructor should always be private to prevent direct @@ -49,17 +48,19 @@ export class BackendClient { * This implementation let you subclass the Singleton class while keeping * just one instance of each subclass around. */ - public static getInstance(): BackendClient | undefined { + public static getInstance(): BackendClient { if (!BackendClient.instance) { BackendClient.instance = new BackendClient() - } + } return BackendClient.instance } public async getHomeCommunityDraft(): Promise { this.logger.info('check home community on backend') const { data, errors } = await this.client.rawRequest<{ homeCommunity: Community }>( - homeCommunityGraphqlQuery, {}, await this.getRequestHeader(), + homeCommunityGraphqlQuery, + {}, + await this.getRequestHeader(), ) if (errors) { throw errors[0] @@ -70,11 +71,13 @@ export class BackendClient { public async setHomeCommunityTopicId(uuid: Uuidv4, hieroTopicId: HieroId): Promise { this.logger.info('update home community on backend') const { data, errors } = await this.client.rawRequest<{ updateHomeCommunity: Community }>( - setHomeCommunityTopicId, { uuid, hieroTopicId }, await this.getRequestHeader(), + setHomeCommunityTopicId, + { uuid, hieroTopicId }, + await this.getRequestHeader(), ) if (errors) { throw errors[0] - } + } return v.parse(communitySchema, data.updateHomeCommunity) } diff --git a/dlt-connector/src/client/backend/community.schema.test.ts b/dlt-connector/src/client/backend/community.schema.test.ts index d39c376ba..e56056377 100644 --- a/dlt-connector/src/client/backend/community.schema.test.ts +++ b/dlt-connector/src/client/backend/community.schema.test.ts @@ -1,24 +1,23 @@ // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' import * as v from 'valibot' -import { uuidv4Schema } from '../../schemas/typeGuard.schema' +import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' import { communitySchema } from './community.schema' -import { hieroIdSchema } from '../../schemas/typeGuard.schema' describe('community.schema', () => { it('community', () => { expect( v.parse(communitySchema, { uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', - topicId: '0.0.4', + hieroTopicId: '0.0.4', foreign: false, - createdAt: '2021-01-01', + creationDate: '2021-01-01', }), ).toEqual({ - topicId: v.parse(hieroIdSchema, '0.0.4'), + hieroTopicId: v.parse(hieroIdSchema, '0.0.4'), uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), foreign: false, - createdAt: new Date('2021-01-01'), + creationDate: new Date('2021-01-01'), }) }) }) diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts index 0222322a4..b74ac49cf 100644 --- a/dlt-connector/src/client/backend/community.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -4,17 +4,13 @@ import { dateSchema } from '../../schemas/typeConverter.schema' import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' /** - * Schema Definitions for rpc call parameter, when dlt-connector is called from backend - */ - -/** - * Schema for community, for creating new CommunityRoot Transaction on gradido blockchain + * Schema Definitions for graphql response */ export const communitySchema = v.object({ uuid: uuidv4Schema, - topicId: v.nullish(hieroIdSchema), + hieroTopicId: v.nullish(hieroIdSchema), foreign: v.boolean('expect boolean type'), - createdAt: dateSchema, + creationDate: dateSchema, }) export type CommunityInput = v.InferInput @@ -25,7 +21,7 @@ export const homeCommunityGraphqlQuery = gql` query { homeCommunity { uuid - topicId + hieroTopicId foreign creationDate } @@ -33,10 +29,10 @@ export const homeCommunityGraphqlQuery = gql` ` export const setHomeCommunityTopicId = gql` - mutation ($uuid: string, $hieroTopicId: string){ + mutation ($uuid: String!, $hieroTopicId: String){ updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { uuid - topicId + hieroTopicId foreign creationDate } diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index a058f1c72..f63ac650a 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -6,7 +6,7 @@ import { PrivateKey, Timestamp, TopicCreateTransaction, - TopicId, + TopicId, TopicInfoQuery, TopicMessageSubmitTransaction, TopicUpdateTransaction, @@ -14,13 +14,13 @@ import { TransactionResponse, Wallet, } from '@hashgraph/sdk' -import { parse } from 'valibot' import { GradidoTransaction, HieroTopicId } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' +import { parse } from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import { topicInfoSchema, type TopicInfoOutput } from './output.schema' +import { type TopicInfoOutput, topicInfoSchema } from './output.schema' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds @@ -29,7 +29,7 @@ export const MAX_AUTORENEW_PERIOD = 8000001 // seconds export class HieroClient { private static instance: HieroClient wallet: Wallet - client: Client + client: Client logger: Logger private constructor() { @@ -43,12 +43,10 @@ export class HieroClient { operatorKey = PrivateKey.fromStringECDSA(CONFIG.HIERO_OPERATOR_KEY) } this.wallet = new Wallet(CONFIG.HIERO_OPERATOR_ID, operatorKey, provider) + this.client.setOperator(CONFIG.HIERO_OPERATOR_ID, operatorKey) } public static getInstance(): HieroClient { - if (!CONFIG.HIERO_ACTIVE) { - throw new Error('hiero is disabled via config...') - } if (!HieroClient.instance) { HieroClient.instance = new HieroClient() } @@ -87,14 +85,14 @@ export class HieroClient { public async getTopicInfo(topicId: HieroId): Promise { const info = await new TopicInfoQuery() - .setTopicId(TopicId.fromString(topicId)) - .execute(this.client) + .setTopicId(TopicId.fromString(topicId)) + .execute(this.client) this.logger.debug(JSON.stringify(info, null, 2)) return parse(topicInfoSchema, { topicId: topicId.toString(), sequenceNumber: info.sequenceNumber.toNumber(), - expirationTime: info.expirationTime?.toString(), - autoRenewPeriod: info.autoRenewPeriod?.seconds, + expirationTime: info.expirationTime?.toDate(), + autoRenewPeriod: info.autoRenewPeriod?.seconds.toNumber(), autoRenewAccountId: info.autoRenewAccountId?.toString(), }) } diff --git a/dlt-connector/src/client/hiero/output.schema.ts b/dlt-connector/src/client/hiero/output.schema.ts index da1864aae..ea99f677a 100644 --- a/dlt-connector/src/client/hiero/output.schema.ts +++ b/dlt-connector/src/client/hiero/output.schema.ts @@ -1,8 +1,8 @@ import * as v from 'valibot' -import { hieroIdSchema } from '../../schemas/typeGuard.schema' import { dateSchema } from '../../schemas/typeConverter.schema' +import { hieroIdSchema } from '../../schemas/typeGuard.schema' -// schema definitions for exporting data from hiero request as json back to caller +// schema definitions for exporting data from hiero request as json back to caller /*export const dateStringSchema = v.pipe( v.enum([v.string(), v.date()], v.transform(in: string | Date) @@ -11,12 +11,11 @@ import { dateSchema } from '../../schemas/typeConverter.schema' export const positiveNumberSchema = v.pipe(v.number(), v.minValue(0)) export const topicInfoSchema = v.object({ - topicId: hieroIdSchema, - sequenceNumber: positiveNumberSchema, - expirationTime: dateSchema, - autoRenewPeriod: v.optional(positiveNumberSchema, 0), - autoRenewAccountId: v.optional(hieroIdSchema, '0.0.0'), + topicId: hieroIdSchema, + sequenceNumber: positiveNumberSchema, + expirationTime: dateSchema, + autoRenewPeriod: v.optional(positiveNumberSchema, 0), + autoRenewAccountId: v.optional(hieroIdSchema, '0.0.0'), }) export type TopicInfoOutput = v.InferOutput - diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index 91dd84707..e0dfc82a3 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -1,3 +1,3 @@ export const LOG4JS_BASE_CATEGORY = 'dlt' // 7 days -export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 \ No newline at end of file +export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 9a9889cda..d4184d9d6 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -1,60 +1,23 @@ -/* eslint-disable n/no-process-env */ import dotenv from 'dotenv' +import { parse, InferOutput, ValiError } from 'valibot' +import { configSchema } from './schema' dotenv.config() -const logging = { - LOG4JS_CONFIG: 'log4js-config.json', - // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL ?? 'info', +type ConfigOutput = InferOutput + +let config: ConfigOutput +console.info('Config loading...') +try { + config = parse(configSchema, process.env) +} catch (error: Error | unknown) { + if (error instanceof ValiError) { + console.error(`${error.issues[0].path[0].key}: ${error.message} received: ${error.issues[0].received}`) + } else { + console.error(error) + } + // console.error('Config error:', JSON.stringify(error, null, 2)) + process.exit(1) } -const server = { - PRODUCTION: process.env.NODE_ENV === 'production', - DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT ?? 6010, -} - -const secrets = { - JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', - GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: - process.env.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET ?? 'invalid', - GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: - process.env.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY ?? 'invalid', -} - -const iota = { - IOTA_HOME_COMMUNITY_SEED: process.env.IOTA_HOME_COMMUNITY_SEED ?? null, -} - -const hiero = { - HIERO_ACTIVE: process.env.HIERO_ACTIVE === 'true' || false, - HIERO_HEDERA_NETWORK: process.env.HIERO_HEDERA_NETWORK ?? 'testnet', - HIERO_OPERATOR_ID: process.env.HIERO_OPERATOR_ID ?? '0.0.2', - HIERO_OPERATOR_KEY: - process.env.HIERO_OPERATOR_KEY ?? - '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', -} - -const apis = { - CONNECT_TIMEOUT_MS: process.env.CONNECT_TIMEOUT_MS - ? Number.parseInt(process.env.CONNECT_TIMEOUT_MS) - : 1000, - CONNECT_RETRY_COUNT: process.env.CONNECT_RETRY_COUNT - ? Number.parseInt(process.env.CONNECT_RETRY_COUNT) - : 15, - CONNECT_RETRY_DELAY_MS: process.env.CONNECT_RETRY_DELAY_MS - ? Number.parseInt(process.env.CONNECT_RETRY_DELAY_MS) - : 500, - IOTA_API_URL: process.env.IOTA_API_URL ?? 'https://chrysalis-nodes.iota.org', - NODE_SERVER_URL: process.env.NODE_SERVER_URL ?? 'http://127.0.0.1:8340', - BACKEND_SERVER_URL: process.env.BACKEND_SERVER_URL ?? 'http://127.0.0.1:4000', -} - -export const CONFIG = { - ...logging, - ...server, - ...secrets, - ...iota, - ...hiero, - ...apis, -} +export const CONFIG = config diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index b9a170e43..3dfe3cbe9 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -1,24 +1,77 @@ +import { MemoryBlock } from 'gradido-blockchain-js' import * as v from 'valibot' -export const HIERO_ACTIVE = v.nullish( - v.boolean('Flag to indicate if the Hiero (Hedera Hashgraph Ledger) service is used.'), - false, -) +const hexSchema = v.pipe(v.string('expect string type'), v.hexadecimal('expect hexadecimal string')) -export const HIERO_HEDERA_NETWORK = v.nullish( - v.union([v.literal('mainnet'), v.literal('testnet'), v.literal('previewnet')]), - 'testnet', -) +const hex16Schema = v.pipe(hexSchema, v.length(32, 'expect string length = 32')) -export const HIERO_OPERATOR_ID = v.nullish( - v.pipe(v.string('The operator ID for Hiero integration'), v.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/)), - '0.0.2', -) - -export const HIERO_OPERATOR_KEY = v.nullish( - v.pipe( - v.string('The operator key for Hiero integration, default is for local default node'), - v.regex(/^[0-9a-fA-F]{64,96}$/), +export const configSchema = v.object({ + LOG4JS_CONFIG: v.optional( + v.string('The path to the log4js configuration file'), + './log4js-config.json', ), - '302e020100300506032b65700422042091132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137', -) + LOG_LEVEL: v.optional(v.string('The log level'), 'info'), + DLT_CONNECTOR_PORT: v.optional( + v.pipe( + v.string('A valid port on which the DLT connector is running'), + v.transform((input: string) => Number(input)), + v.minValue(1), + v.maxValue(65535), + ), + '6010', + ), + JWT_SECRET: v.pipe( + v.string('The JWT secret for connecting to the backend'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === 'secret123') { + return false + } + return true + }, "Shouldn't use default value in production"), + ), + GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: hexSchema, + GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: hex16Schema, + HOME_COMMUNITY_SEED: v.pipe( + hexSchema, + v.length(64, 'expect seed length minimum 64 characters (32 Bytes)'), + v.transform((input: string) => MemoryBlock.fromHex(input)), + ), + HIERO_HEDERA_NETWORK: v.optional( + v.union([v.literal('mainnet'), v.literal('testnet'), v.literal('previewnet')]), + 'testnet', + ), + HIERO_OPERATOR_ID: v.pipe( + v.string('The operator ID (Account id) for Hiero integration'), + v.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/), + ), + HIERO_OPERATOR_KEY: v.pipe( + v.string('The operator key (Private key) for Hiero integration'), + v.hexadecimal(), + v.minLength(64), + v.maxLength(96), + ), + CONNECT_TIMEOUT_MS: v.optional( + v.pipe(v.number('The connection timeout in milliseconds'), v.minValue(200), v.maxValue(120000)), + 1000, + ), + CONNECT_RETRY_COUNT: v.optional( + v.pipe(v.number('The connection retry count'), v.minValue(1), v.maxValue(50)), + 15, + ), + CONNECT_RETRY_DELAY_MS: v.optional( + v.pipe( + v.number('The connection retry delay in milliseconds'), + v.minValue(100), + v.maxValue(10000), + ), + 500, + ), + NODE_SERVER_URL: v.optional( + v.string('The URL of the gradido node server'), + 'http://localhost:6010', + ), + BACKEND_SERVER_URL: v.optional( + v.string('The URL of the gradido backend server'), + 'http://localhost:6010', + ), +}) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 437d9a458..1563d4b53 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -17,7 +17,7 @@ export class KeyPairIdentifierLogic { isUserKeyPair(): boolean { return ( this.identifier.seed === undefined && - this.identifier.account != undefined && + this.identifier.account != null && this.identifier.account.accountNr === 0 ) } @@ -25,7 +25,7 @@ export class KeyPairIdentifierLogic { isAccountKeyPair(): boolean { return ( this.identifier.seed === undefined && - this.identifier.account != undefined && + this.identifier.account != null && this.identifier.account.accountNr > 0 ) } diff --git a/dlt-connector/src/errors.ts b/dlt-connector/src/errors.ts index e9cbaee98..3bedb023a 100644 --- a/dlt-connector/src/errors.ts +++ b/dlt-connector/src/errors.ts @@ -35,6 +35,20 @@ export class GradidoNodeInvalidTransactionError extends GradidoNodeError { } } +export class GradidoBlockchainError extends Error { + constructor(message: string) { + super(message) + this.name = 'GradidoBlockchainError' + } +} + +export class GradidoBlockchainCryptoError extends GradidoBlockchainError { + constructor(message: string) { + super(message) + this.name = 'GradidoBlockchainCryptoError' + } +} + export class ParameterError extends Error { constructor(message: string) { super(message) diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index de0b07729..733bbcfc0 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,83 +1,111 @@ import { readFileSync } from 'node:fs' import { Elysia } from 'elysia' import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' -import { configure, getLogger } from 'log4js' -import * as v from 'valibot' +import { configure, getLogger, Logger } from 'log4js' +import { parse } from 'valibot' import { BackendClient } from './client/backend/BackendClient' +import { GradidoNodeClient } from './client/GradidoNode/GradidoNodeClient' import { HieroClient } from './client/hiero/HieroClient' -import { getTransaction } from './client/GradidoNode/api' import { CONFIG } from './config' -import { SendToIotaContext } from './interactions/sendToIota/SendToIota.context' -import { KeyPairCacheManager } from './KeyPairCacheManager' -import { keyGenerationSeedSchema } from './schemas/base.schema' -import { isPortOpenRetry } from './utils/network' -import { appRoutes } from './server' import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' +import { SendToHieroContext } from './interactions/sendToHiero/SendToHiero.context' +import { KeyPairCacheManager } from './KeyPairCacheManager' +import { Community, communitySchema } from './schemas/transaction.schema' +import { appRoutes } from './server' +import { isPortOpenRetry } from './utils/network' + +type Clients = { + backend: BackendClient + hiero: HieroClient + gradidoNode: GradidoNodeClient +} async function main() { + // load everything from .env + const logger = loadConfig() + const clients = createClients() + const { hiero, gradidoNode } = clients + + // show hiero account balance, double also as check if valid hiero account was given in config + const balance = await hiero.getBalance() + logger.info(`Hiero Account Balance: ${balance.hbars.toString()}`) + + // get home community, create topic if not exist, or check topic expiration and update it if needed + const homeCommunity = await homeCommunitySetup(clients, logger) + + // ask gradido node if community blockchain was created + try { + if ( + !(await gradidoNode.getTransaction({ transactionId: 1, topic: homeCommunity.hieroTopicId })) + ) { + // if not exist, create community root transaction + await SendToHieroContext(homeCommunity) + } + } catch (e) { + logger.error(`error requesting gradido node: ${e}`) + } + // listen for rpc request from backend (graphql replaced with elysiaJS) + new Elysia().use(appRoutes).listen(CONFIG.DLT_CONNECTOR_PORT, () => { + logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) + }) +} + +function loadConfig(): Logger { // configure log4js // TODO: replace late by loader from config-schema const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) configure(options) const logger = getLogger('dlt') - // check if valid seed for root key pair generation is present - if (!v.safeParse(keyGenerationSeedSchema, CONFIG.IOTA_HOME_COMMUNITY_SEED).success) { - logger.error('IOTA_HOME_COMMUNITY_SEED must be a valid hex string, at least 64 characters long') - process.exit(1) - } // load crypto keys for gradido blockchain lib loadCryptoKeys( MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY), ) + return logger +} - // ask backend for home community if we haven't one - const backend = BackendClient.getInstance() - if (!backend) { - throw new Error('cannot create backend client') - } - const hieroClient = HieroClient.getInstance() - if (!hieroClient) { - throw new Error('cannot create hiero client') +// needed to be called after loading config +function createClients(): Clients { + return { + backend: BackendClient.getInstance(), + hiero: HieroClient.getInstance(), + gradidoNode: GradidoNodeClient.getInstance(), } +} + +async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): Promise { // wait for backend server await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) + // ask backend for home community let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one - if (!homeCommunity.topicId) { - const topicId = await hieroClient.createTopic() + if (!homeCommunity.hieroTopicId) { + const topicId = await hiero.createTopic() + // update topic on backend server homeCommunity = await backend.setHomeCommunityTopicId(homeCommunity.uuid, topicId) } else { // if topic exist, check if we need to update it - let topicInfo = await hieroClient.getTopicInfo(homeCommunity.topicId) - if (topicInfo.expirationTime.getTime() - new Date().getTime() < MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE) { - await hieroClient.updateTopic(homeCommunity.topicId) - topicInfo = await hieroClient.getTopicInfo(homeCommunity.topicId) - logger.info('updated topic info, new expiration time: %s', topicInfo.expirationTime.toLocaleDateString()) + let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) + if ( + topicInfo.expirationTime.getTime() - new Date().getTime() < + MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE + ) { + await hiero.updateTopic(homeCommunity.hieroTopicId) + topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) + logger.info( + `updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`, + ) } } - if (!homeCommunity.topicId) { + if (!homeCommunity.hieroTopicId) { throw new Error('still no topic id, after creating topic and update community in backend.') } - KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.topicId) - logger.info('home community topic: %s', homeCommunity.topicId) - logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) - // ask gradido node if community blockchain was created - try { - if (!(await getTransaction({ transactionNr: 1, topic: homeCommunity.topicId }))) { - // if not exist, create community root transaction - await SendToIotaContext(homeCommunity) - } - } catch (e) { - logger.error('error requesting gradido node: ', e) - } - // listen for rpc request from backend (graphql replaced with trpc and elysia) - new Elysia() - .use(appRoutes) - .listen(CONFIG.DLT_CONNECTOR_PORT, () => { - logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) - }) + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.hieroTopicId) + logger.info(`home community topic: ${homeCommunity.hieroTopicId}`) + logger.info(`gradido node server: ${CONFIG.NODE_SERVER_URL}`) + logger.info(`gradido backend server: ${CONFIG.BACKEND_SERVER_URL}`) + return parse(communitySchema, homeCommunity) } main().catch((e) => { diff --git a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts index 62ce06ecf..4296c1fcf 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts @@ -1,5 +1,5 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' - +import { GradidoBlockchainCryptoError } from '../../errors' import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class AccountKeyPairRole extends AbstractKeyPairRole { @@ -11,6 +11,12 @@ export class AccountKeyPairRole extends AbstractKeyPairRole { } public generateKeyPair(): KeyPairEd25519 { - return this.userKeyPair.deriveChild(this.accountNr) + const keyPair = this.userKeyPair.deriveChild(this.accountNr) + if (!keyPair) { + throw new GradidoBlockchainCryptoError( + `KeyPairEd25519 child derivation failed, has private key: ${this.userKeyPair.hasPrivateKey()}, accountNr: ${this.accountNr}`, + ) + } + return keyPair } } diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts index 0d73d891d..8911b8851 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts @@ -1,24 +1,19 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' - -import { getTransaction } from '../../client/GradidoNode/api' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { GradidoNodeInvalidTransactionError, GradidoNodeMissingTransactionError, } from '../../errors' -import { HieroId } from '../../schemas/typeGuard.schema' import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { - public constructor(communityTopicId: HieroId) { - super(communityTopicId) - } - public async retrieveKeyPair(): Promise { const transactionIdentifier = { - transactionNr: 1, + transactionId: 1, topic: this.topic, } - const firstTransaction = await getTransaction(transactionIdentifier) + const firstTransaction = + await GradidoNodeClient.getInstance().getTransaction(transactionIdentifier) if (!firstTransaction) { throw new GradidoNodeMissingTransactionError('Cannot find transaction', transactionIdentifier) } diff --git a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts index 81b9a016c..20d1ec2a1 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts @@ -1,4 +1,4 @@ -import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { KeyPairEd25519 } from 'gradido-blockchain-js' import { CONFIG } from '../../config' import { ParameterError } from '../../errors' @@ -6,16 +6,9 @@ import { AbstractKeyPairRole } from './AbstractKeyPair.role' export class HomeCommunityKeyPairRole extends AbstractKeyPairRole { public generateKeyPair(): KeyPairEd25519 { - // TODO: prevent this check with valibot test on config - if (!CONFIG.IOTA_HOME_COMMUNITY_SEED) { - throw new Error( - 'IOTA_HOME_COMMUNITY_SEED is missing either in config or as environment variable', - ) - } - const seed = MemoryBlock.fromHex(CONFIG.IOTA_HOME_COMMUNITY_SEED) - const keyPair = KeyPairEd25519.create(seed) + const keyPair = KeyPairEd25519.create(CONFIG.HOME_COMMUNITY_SEED) if (!keyPair) { - throw new ParameterError("couldn't create keyPair from IOTA_HOME_COMMUNITY_SEED") + throw new ParameterError("couldn't create keyPair from HOME_COMMUNITY_SEED") } return keyPair } diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts index d1658d608..524c3dc1a 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts @@ -1,6 +1,5 @@ import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' - -import { findUserByNameHash } from '../../client/GradidoNode/api' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { Uuidv4Hash } from '../../data/Uuidv4Hash' import { GradidoNodeMissingUserError, ParameterError } from '../../errors' import { IdentifierAccount } from '../../schemas/account.schema' @@ -16,7 +15,7 @@ export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { throw new ParameterError('missing account') } - const accountPublicKey = await findUserByNameHash( + const accountPublicKey = await GradidoNodeClient.getInstance().findUserByNameHash( new Uuidv4Hash(this.identifier.account.userUuid), this.topic, ) diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts index a2f57898c..01120eceb 100644 --- a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts +++ b/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts @@ -1,5 +1,5 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' - +import { GradidoBlockchainCryptoError } from '../../errors' import { hardenDerivationIndex } from '../../utils/derivationHelper' import { AbstractKeyPairRole } from './AbstractKeyPair.role' @@ -21,9 +21,14 @@ export class UserKeyPairRole extends AbstractKeyPairRole { parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) } // parts: [2206563009, 2629978174, 2324817329, 2405141782] - return parts.reduce( - (keyPair: KeyPairEd25519, node: number) => keyPair.deriveChild(node), - this.communityKeys, - ) + return parts.reduce((keyPair: KeyPairEd25519, node: number) => { + const localKeyPair = keyPair.deriveChild(node) + if (!localKeyPair) { + throw new GradidoBlockchainCryptoError( + `KeyPairEd25519 child derivation failed, has private key: ${keyPair.hasPrivateKey()} for user: ${this.userUuid}`, + ) + } + return localKeyPair + }, this.communityKeys) } } diff --git a/dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/AbstractTransaction.role.ts similarity index 100% rename from dlt-connector/src/interactions/sendToIota/AbstractTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/AbstractTransaction.role.ts diff --git a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts similarity index 68% rename from dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts index c59939ccb..34299683a 100644 --- a/dlt-connector/src/interactions/sendToIota/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts @@ -1,6 +1,7 @@ import { GradidoTransactionBuilder } from 'gradido-blockchain-js' -import { Community } from '../../client/backend/community.schema' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { GradidoBlockchainCryptoError } from '../../errors' +import { Community } from '../../schemas/transaction.schema' import { HieroId } from '../../schemas/typeGuard.schema' import { AUF_ACCOUNT_DERIVATION_INDEX, @@ -16,7 +17,7 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole { } getSenderCommunityTopicId(): HieroId { - return this.community.topicId + return this.community.hieroTopicId } getRecipientCommunityTopicId(): HieroId { @@ -26,16 +27,26 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const communityKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ communityTopicId: this.community.topicId }), + new KeyPairIdentifierLogic({ communityTopicId: this.community.hieroTopicId }), ) const gmwKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), - ) // as unknown as KeyPairEd25519 + ) + if (!gmwKeyPair) { + throw new GradidoBlockchainCryptoError( + `KeyPairEd25519 child derivation failed, has private key: ${communityKeyPair.hasPrivateKey()} for community: ${this.community.uuid}`, + ) + } const aufKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX), - ) // as unknown as KeyPairEd25519 + ) + if (!aufKeyPair) { + throw new GradidoBlockchainCryptoError( + `KeyPairEd25519 child derivation failed, has private key: ${communityKeyPair.hasPrivateKey()} for community: ${this.community.uuid}`, + ) + } builder - .setCreatedAt(this.community.createdAt) + .setCreatedAt(this.community.creationDate) .setCommunityRoot( communityKeyPair.getPublicKey(), gmwKeyPair.getPublicKey(), diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts similarity index 100% rename from dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts diff --git a/dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts similarity index 100% rename from dlt-connector/src/interactions/sendToIota/DeferredTransferTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts diff --git a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts similarity index 95% rename from dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 3d2574681..a91990360 100644 --- a/dlt-connector/src/interactions/sendToIota/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,6 +1,6 @@ import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' import { parse } from 'valibot' -import { getTransactionsForAccount } from '../../client/GradidoNode/api' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { RedeemDeferredTransferTransaction, @@ -42,7 +42,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo throw new Error("redeem deferred transfer: couldn't calculate sender public key") } // load deferred transfer transaction from gradido node - const transactions = await getTransactionsForAccount( + const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( { maxResultCount: 2, topic: this.getSenderCommunityTopicId() }, senderPublicKey.convertToHex(), ) diff --git a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts similarity index 94% rename from dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index 5eee0f164..64076b920 100644 --- a/dlt-connector/src/interactions/sendToIota/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -1,4 +1,4 @@ -import { GradidoTransactionBuilder } from 'gradido-blockchain-js' +import { AddressType, GradidoTransactionBuilder } from 'gradido-blockchain-js' import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { Uuidv4Hash } from '../../data/Uuidv4Hash' @@ -53,7 +53,7 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { .setCreatedAt(this.registerAddressTransaction.createdAt) .setRegisterAddress( userKeyPair.getPublicKey(), - this.registerAddressTransaction.accountType, + this.registerAddressTransaction.accountType as AddressType, new Uuidv4Hash(this.account.userUuid).getAsMemoryBlock(), accountKeyPair.getPublicKey(), ) diff --git a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts similarity index 83% rename from dlt-connector/src/interactions/sendToIota/SendToIota.context.ts rename to dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 4b8b32c34..c363ad263 100644 --- a/dlt-connector/src/interactions/sendToIota/SendToIota.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -1,16 +1,25 @@ import { GradidoTransaction, - InteractionValidate, - MemoryBlock, + InteractionValidate, + MemoryBlock, ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { safeParse, parse } from 'valibot' -import { Community, communitySchema } from '../../client/backend/community.schema' +import { parse, safeParse } from 'valibot' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { Transaction, transactionSchema } from '../../schemas/transaction.schema' -import { HieroId, HieroTransactionId, hieroTransactionIdSchema } from '../../schemas/typeGuard.schema' +import { InputTransactionType } from '../../enum/InputTransactionType' +import { + Community, + communitySchema, + Transaction, + transactionSchema, +} from '../../schemas/transaction.schema' +import { + HieroId, + HieroTransactionId, + hieroTransactionIdSchema, +} from '../../schemas/typeGuard.schema' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' @@ -18,16 +27,15 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' -import { InputTransactionType } from '../../enum/InputTransactionType' -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToIota.SendToIotaContext`) +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) /** * @DCI-Context - * Context for sending transaction to iota - * send every transaction only once to iota! + * Context for sending transaction to hiero + * send every transaction only once to hiero! */ -export async function SendToIotaContext( +export async function SendToHieroContext( input: Transaction | Community, ): Promise { // let gradido blockchain validator run, it will throw an exception when something is wrong @@ -44,7 +52,7 @@ export async function SendToIotaContext( const client = HieroClient.getInstance() const resultMessage = await client.sendMessage(topic, gradidoTransaction) const transactionId = resultMessage.response.transactionId.toString() - logger.info('transmitted Gradido Transaction to Iota', { transactionId }) + logger.info('transmitted Gradido Transaction to Hiero', { transactionId }) return transactionId } @@ -75,7 +83,7 @@ export async function SendToIotaContext( } } - const role = chooseCorrectRole(input) + const role = chooseCorrectRole(input) const builder = await role.getGradidoTransactionBuilder() if (builder.isCrossCommunityTransaction()) { const outboundTransaction = builder.buildOutbound() @@ -92,10 +100,7 @@ export async function SendToIotaContext( } else { const transaction = builder.build() validate(transaction) - const iotaMessageId = await sendViaHiero( - transaction, - role.getSenderCommunityTopicId(), - ) + const iotaMessageId = await sendViaHiero(transaction, role.getSenderCommunityTopicId()) return parse(hieroTransactionIdSchema, iotaMessageId) } } diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts similarity index 90% rename from dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts rename to dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts index f244bf472..473bfbc1e 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts @@ -7,13 +7,13 @@ import { import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { + Transaction, TransferTransaction, transferTransactionSchema, - Transaction, } from '../../schemas/transaction.schema' +import { HieroId } from '../../schemas/typeGuard.schema' import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' import { AbstractTransactionRole } from './AbstractTransaction.role' -import { HieroId } from '../../schemas/typeGuard.schema' export class TransferTransactionRole extends AbstractTransactionRole { private transferTransaction: TransferTransaction @@ -33,7 +33,9 @@ export class TransferTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() // sender + signer - const senderKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(this.transferTransaction.user)) + const senderKeyPair = await KeyPairCalculation( + new KeyPairIdentifierLogic(this.transferTransaction.user), + ) // recipient const recipientKeyPair = await KeyPairCalculation( new KeyPairIdentifierLogic(this.transferTransaction.linkedUser), @@ -56,9 +58,7 @@ export class TransferTransactionRole extends AbstractTransactionRole { const recipientCommunity = this.transferTransaction.linkedUser.communityTopicId if (senderCommunity !== recipientCommunity) { // we have a cross group transaction - builder - .setSenderCommunity(senderCommunity) - .setRecipientCommunity(recipientCommunity) + builder.setSenderCommunity(senderCommunity).setRecipientCommunity(recipientCommunity) } builder.sign(senderKeyPair) return builder diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index e8d8326c6..61f485db6 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -1,25 +1,19 @@ -import { describe, expect, it, beforeAll } from 'bun:test' +import { beforeAll, describe, expect, it } from 'bun:test' import { randomBytes } from 'crypto' import { v4 as uuidv4 } from 'uuid' import { parse } from 'valibot' import { InputTransactionType } from '../enum/InputTransactionType' import { - TransactionInput, - transactionSchema, -} from './transaction.schema' -import { transactionIdentifierSchema } from '../client/GradidoNode/input.schema' -import { - gradidoAmountSchema, - HieroId, - hieroIdSchema, - HieroTransactionId, - hieroTransactionIdSchema, - Memo, - memoSchema, - timeoutDurationSchema, - Uuidv4, - uuidv4Schema + gradidoAmountSchema, + HieroId, + hieroIdSchema, + Memo, + memoSchema, + timeoutDurationSchema, + Uuidv4, + uuidv4Schema, } from '../schemas/typeGuard.schema' +import { TransactionInput, transactionSchema } from './transaction.schema' const transactionLinkCode = (date: Date): string => { const time = date.getTime().toString(16) @@ -31,197 +25,150 @@ const transactionLinkCode = (date: Date): string => { } let topic: HieroId const topicString = '0.0.261' -let hieroTransactionId: HieroTransactionId beforeAll(() => { topic = parse(hieroIdSchema, topicString) - hieroTransactionId = parse(hieroTransactionIdSchema, '0.0.261-1755348116-1281621') }) describe('transaction schemas', () => { - describe('transactionIdentifierSchema ', () => { - it('valid, transaction identified by transactionNr and topic', () => { - expect( - parse(transactionIdentifierSchema, { - transactionNr: 1, - topic: topicString, - }), - ).toEqual({ - transactionNr: 1, - hieroTransactionId: undefined, - topic, - }) + let userUuid: Uuidv4 + let userUuidString: string + let memoString: string + let memo: Memo + beforeAll(() => { + userUuidString = uuidv4() + userUuid = parse(uuidv4Schema, userUuidString) + memoString = 'TestMemo' + memo = parse(memoSchema, memoString) + }) + it('valid, register new user address', () => { + const registerAddress: TransactionInput = { + user: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + type: InputTransactionType.REGISTER_ADDRESS, + createdAt: '2022-01-01T00:00:00.000Z', + } + expect(parse(transactionSchema, registerAddress)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + type: registerAddress.type, + createdAt: new Date(registerAddress.createdAt), }) - it('valid, transaction identified by hieroTransactionId and topic', () => { - expect( - parse(transactionIdentifierSchema, { - hieroTransactionId: '0.0.261-1755348116-1281621', - topic: topicString, - }), - ).toEqual({ - hieroTransactionId, - topic - }) - }) - it('invalid, missing topic', () => { - expect(() => - parse(transactionIdentifierSchema, { - transactionNr: 1, - hieroTransactionId: '0.0.261-1755348116-1281621', - }), - ).toThrowError(new Error('Invalid key: Expected "topic" but received undefined')) - }) - it('invalid, transactionNr and iotaMessageId set', () => { - expect(() => - parse(transactionIdentifierSchema, { - transactionNr: 1, - hieroTransactionId: '0.0.261-1755348116-1281621', - topic - }), - ).toThrowError(new Error('expect transactionNr or hieroTransactionId not both')) + }) + it('valid, gradido transfer', () => { + const gradidoTransfer: TransactionInput = { + user: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + linkedUser: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + amount: '100', + memo: memoString, + type: InputTransactionType.GRADIDO_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + } + expect(parse(transactionSchema, gradidoTransfer)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + linkedUser: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + amount: parse(gradidoAmountSchema, gradidoTransfer.amount!), + memo, + type: gradidoTransfer.type, + createdAt: new Date(gradidoTransfer.createdAt), }) }) - describe('transactionSchema', () => { - let userUuid: Uuidv4 - let userUuidString: string - let memoString: string - let memo: Memo - beforeAll(() => { - userUuidString = uuidv4() - userUuid = parse(uuidv4Schema, userUuidString) - memoString = 'TestMemo' - memo = parse(memoSchema, memoString) + it('valid, gradido creation', () => { + const gradidoCreation: TransactionInput = { + user: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + linkedUser: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, + }, + amount: '1000', + memo: memoString, + type: InputTransactionType.GRADIDO_CREATION, + createdAt: '2022-01-01T00:00:00.000Z', + targetDate: '2021-11-01T10:00', + } + expect(parse(transactionSchema, gradidoCreation)).toEqual({ + user: { + communityTopicId: topic, + account: { userUuid, accountNr: 0 }, + }, + linkedUser: { + communityTopicId: topic, + account: { userUuid, accountNr: 0 }, + }, + amount: parse(gradidoAmountSchema, gradidoCreation.amount!), + memo, + type: gradidoCreation.type, + createdAt: new Date(gradidoCreation.createdAt), + targetDate: new Date(gradidoCreation.targetDate!), }) - it('valid, register new user address', () => { - const registerAddress: TransactionInput = { - user: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, + }) + it('valid, gradido transaction link / deferred transfer', () => { + const gradidoTransactionLink: TransactionInput = { + user: { + communityTopicId: topicString, + account: { + userUuid: userUuidString, }, - type: InputTransactionType.REGISTER_ADDRESS, - createdAt: '2022-01-01T00:00:00.000Z', - } - expect(parse(transactionSchema, registerAddress)).toEqual({ - user: { - communityTopicId: topic, - account: { - userUuid, - accountNr: 0, - }, + }, + linkedUser: { + communityTopicId: topicString, + seed: { + seed: transactionLinkCode(new Date()), }, - type: registerAddress.type, - createdAt: new Date(registerAddress.createdAt), - }) - }) - it('valid, gradido transfer', () => { - const gradidoTransfer: TransactionInput = { - user: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, + }, + amount: '100', + memo: memoString, + type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, + createdAt: '2022-01-01T00:00:00.000Z', + timeoutDuration: 60 * 60 * 24 * 30, + } + expect(parse(transactionSchema, gradidoTransactionLink)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, }, - linkedUser: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, + }, + linkedUser: { + communityTopicId: topic, + seed: { + seed: gradidoTransactionLink.linkedUser!.seed!.seed, }, - amount: '100', - memo: memoString, - type: InputTransactionType.GRADIDO_TRANSFER, - createdAt: '2022-01-01T00:00:00.000Z', - } - expect(parse(transactionSchema, gradidoTransfer)).toEqual({ - user: { - communityTopicId: topic, - account: { - userUuid, - accountNr: 0, - }, - }, - linkedUser: { - communityTopicId: topic, - account: { - userUuid, - accountNr: 0, - }, - }, - amount: parse(gradidoAmountSchema, gradidoTransfer.amount!), - memo, - type: gradidoTransfer.type, - createdAt: new Date(gradidoTransfer.createdAt), - }) - }) - - it('valid, gradido creation', () => { - const gradidoCreation: TransactionInput = { - user: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, - }, - linkedUser: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, - }, - amount: '1000', - memo: memoString, - type: InputTransactionType.GRADIDO_CREATION, - createdAt: '2022-01-01T00:00:00.000Z', - targetDate: '2021-11-01T10:00', - } - expect(parse(transactionSchema, gradidoCreation)).toEqual({ - user: { - communityTopicId: topic, - account: { userUuid, accountNr: 0 }, - }, - linkedUser: { - communityTopicId: topic, - account: { userUuid, accountNr: 0 }, - }, - amount: parse(gradidoAmountSchema, gradidoCreation.amount!), - memo, - type: gradidoCreation.type, - createdAt: new Date(gradidoCreation.createdAt), - targetDate: new Date(gradidoCreation.targetDate!), - }) - }) - it('valid, gradido transaction link / deferred transfer', () => { - const gradidoTransactionLink: TransactionInput = { - user: { - communityTopicId: topicString, - account: { - userUuid: userUuidString, - }, - }, - linkedUser: { - communityTopicId: topicString, - seed: { - seed: transactionLinkCode(new Date()), - }, - }, - amount: '100', - memo: memoString, - type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, - createdAt: '2022-01-01T00:00:00.000Z', - timeoutDuration: 60 * 60 * 24 * 30, - } - expect(parse(transactionSchema, gradidoTransactionLink)).toEqual({ - user: { - communityTopicId: topic, - account: { - userUuid, - accountNr: 0, - }, - }, - linkedUser: { - communityTopicId: topic, - seed: { - seed: gradidoTransactionLink.linkedUser!.seed!.seed, - }, - }, - amount: parse(gradidoAmountSchema, gradidoTransactionLink.amount!), - memo, - type: gradidoTransactionLink.type, - createdAt: new Date(gradidoTransactionLink.createdAt), - timeoutDuration: parse(timeoutDurationSchema, gradidoTransactionLink.timeoutDuration!), - }) + }, + amount: parse(gradidoAmountSchema, gradidoTransactionLink.amount!), + memo, + type: gradidoTransactionLink.type, + createdAt: new Date(gradidoTransactionLink.createdAt), + timeoutDuration: parse(timeoutDurationSchema, gradidoTransactionLink.timeoutDuration!), }) }) }) diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index de75bda89..4345ec901 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -11,8 +11,22 @@ import { hieroIdSchema, memoSchema, timeoutDurationSchema, + uuidv4Schema, } from './typeGuard.schema' +/** + * Schema for community, for creating new CommunityRoot Transaction on gradido blockchain + */ +export const communitySchema = v.object({ + uuid: uuidv4Schema, + hieroTopicId: hieroIdSchema, + foreign: v.boolean('expect boolean type'), + creationDate: dateSchema, +}) + +export type CommunityInput = v.InferInput +export type Community = v.InferOutput + export const transactionSchema = v.object({ user: identifierAccountSchema, linkedUser: v.nullish(identifierAccountSchema, undefined), diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index 2ec02d12e..71cae3619 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -51,10 +51,10 @@ describe('basic.schema', () => { it('confirmedTransactionSchema', () => { const confirmedTransaction = v.parse( confirmedTransactionSchema, - 'CAcSAgoAGgYIwvK5/wUiAzMuNCogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + 'CAcS5AEKZgpkCiCBZwMplGmI7fRR9MQkaR2Dz1qQQ5BCiC1btyJD71Ue9BJABODQ9sS70th9yHn8X3K+SNv2gsiIdX/V09baCvQCb+yEj2Dd/fzShIYqf3pooIMwJ01BkDJdNGBZs5MDzEAkChJ6ChkIAhIVRGFua2UgZnVlciBkZWluIFNlaW4hEggIgMy5/wUQABoDMy41IAAyTAooCiDbDtYSWhTwMKvtG/yDHgohjPn6v87n7NWBwMDniPAXxxCUmD0aABIgJE0o18xb6P6PsNjh0bkN52AzhggteTzoh09jV+blMq0aCAjC8rn/BRAAIgMzLjUqICiljeEjGHifWe4VNzoe+DN9oOLNZvJmv3VlkP+1RH7MMiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADomCiDbDtYSWhTwMKvtG/yDHgohjPn6v87n7NWBwMDniPAXxxDAhD06JwogJE0o18xb6P6PsNjh0bkN52AzhggteTzoh09jV+blMq0Q65SlBA==', ) expect(confirmedTransaction.getId()).toBe(7) expect(confirmedTransaction.getConfirmedAt().getSeconds()).toBe(1609464130) - expect(confirmedTransaction.getVersionNumber()).toBe('3.4') + expect(confirmedTransaction.getVersionNumber()).toBe('3.5') }) }) diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 3fb6e55ba..4410b54be 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -1,6 +1,7 @@ -import { AddressType, ConfirmedTransaction } from 'gradido-blockchain-js' +import { ConfirmedTransaction } from 'gradido-blockchain-js' import * as v from 'valibot' import { AccountType } from '../enum/AccountType' +import { AddressType } from '../enum/AddressType' import { confirmedTransactionFromBase64, isAddressType, diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 7bf2a85c6..c3a00d4e3 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,50 +1,27 @@ +import { TypeBoxFromValibot } from '@sinclair/typemap' import { Elysia, status } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { parse } from 'valibot' -import { getAddressType } from '../client/GradidoNode/api' +import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' import { LOG4JS_BASE_CATEGORY } from '../config/const' import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' -import { SendToIotaContext } from '../interactions/sendToIota/SendToIota.context' +import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' import { IdentifierAccount, identifierAccountSchema } from '../schemas/account.schema' +import { transactionSchema } from '../schemas/transaction.schema' import { hieroTransactionIdSchema } from '../schemas/typeGuard.schema' import { accountIdentifierSeedSchema, accountIdentifierUserSchema, existSchema, } from './input.schema' -import { TypeBoxFromValibot } from '@sinclair/typemap' -import { transactionSchema } from '../schemas/transaction.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) -async function isAccountExist(identifierAccount: IdentifierAccount): Promise { - const startTime = Date.now() - const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(identifierAccount)) - const publicKey = accountKeyPair.getPublicKey() - if (!publicKey) { - throw status(404, "couldn't calculate account key pair") - } - - // ask gradido node server for account type, if type !== NONE account exist - const addressType = await getAddressType( - publicKey.convertToHex(), - identifierAccount.communityTopicId, - ) - const endTime = Date.now() - logger.info( - `isAccountExist: ${addressType !== AddressType_NONE}, time used: ${endTime - startTime}ms`, - ) - if (logger.isDebugEnabled()) { - logger.debug('params', identifierAccount) - } - return addressType !== AddressType_NONE -} - export const appRoutes = new Elysia() .get( - '/isAccountExist/:communityTopicId/:userUuid/:accountNr', + '/isAccountExist/by-user/:communityTopicId/:userUuid/:accountNr', async ({ params: { communityTopicId, userUuid, accountNr } }) => { const accountIdentifier = parse(identifierAccountSchema, { communityTopicId, @@ -56,7 +33,7 @@ export const appRoutes = new Elysia() { params: accountIdentifierUserSchema, response: existSchema }, ) .get( - '/isAccountExist/:communityTopicId/:seed', + '/isAccountExist/by-seed/:communityTopicId/:seed', async ({ params: { communityTopicId, seed } }) => { const accountIdentifier = parse(identifierAccountSchema, { communityTopicId, @@ -69,7 +46,33 @@ export const appRoutes = new Elysia() ) .post( '/sendTransaction', - async ({ body }) => await SendToIotaContext(parse(transactionSchema, body)), + async ({ body }) => await SendToHieroContext(parse(transactionSchema, body)), // validation schemas - { body: TypeBoxFromValibot(transactionSchema), response: TypeBoxFromValibot(hieroTransactionIdSchema) }, + { + body: TypeBoxFromValibot(transactionSchema), + response: TypeBoxFromValibot(hieroTransactionIdSchema), + }, ) + +async function isAccountExist(identifierAccount: IdentifierAccount): Promise { + const startTime = Date.now() + const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(identifierAccount)) + const publicKey = accountKeyPair.getPublicKey() + if (!publicKey) { + throw status(404, "couldn't calculate account key pair") + } + + // ask gradido node server for account type, if type !== NONE account exist + const addressType = await GradidoNodeClient.getInstance().getAddressType( + publicKey.convertToHex(), + identifierAccount.communityTopicId, + ) + const endTime = Date.now() + logger.info( + `isAccountExist: ${addressType !== AddressType_NONE}, time used: ${endTime - startTime}ms`, + ) + if (logger.isDebugEnabled()) { + logger.debug('params', identifierAccount) + } + return addressType !== AddressType_NONE +} diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 6ab72b069..5b1279beb 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -1,19 +1,11 @@ import { - AddressType, - AddressType_COMMUNITY_AUF, - AddressType_COMMUNITY_GMW, - AddressType_COMMUNITY_HUMAN, - AddressType_COMMUNITY_PROJECT, - AddressType_CRYPTO_ACCOUNT, - AddressType_DEFERRED_TRANSFER, - AddressType_NONE, - AddressType_SUBACCOUNT, ConfirmedTransaction, DeserializeType_CONFIRMED_TRANSACTION, InteractionDeserialize, MemoryBlock, } from 'gradido-blockchain-js' import { AccountType } from '../enum/AccountType' +import { AddressType } from '../enum/AddressType' export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64)) @@ -34,14 +26,14 @@ export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransac * AccountType is the enum defined in TypeScript but with the same options */ const accountToAddressMap: Record = { - [AccountType.COMMUNITY_AUF]: AddressType_COMMUNITY_AUF, - [AccountType.COMMUNITY_GMW]: AddressType_COMMUNITY_GMW, - [AccountType.COMMUNITY_HUMAN]: AddressType_COMMUNITY_HUMAN, - [AccountType.COMMUNITY_PROJECT]: AddressType_COMMUNITY_PROJECT, - [AccountType.CRYPTO_ACCOUNT]: AddressType_CRYPTO_ACCOUNT, - [AccountType.SUBACCOUNT]: AddressType_SUBACCOUNT, - [AccountType.DEFERRED_TRANSFER]: AddressType_DEFERRED_TRANSFER, - [AccountType.NONE]: AddressType_NONE, + [AccountType.COMMUNITY_AUF]: AddressType.COMMUNITY_AUF, + [AccountType.COMMUNITY_GMW]: AddressType.COMMUNITY_GMW, + [AccountType.COMMUNITY_HUMAN]: AddressType.COMMUNITY_HUMAN, + [AccountType.COMMUNITY_PROJECT]: AddressType.COMMUNITY_PROJECT, + [AccountType.CRYPTO_ACCOUNT]: AddressType.CRYPTO_ACCOUNT, + [AccountType.SUBACCOUNT]: AddressType.SUBACCOUNT, + [AccountType.DEFERRED_TRANSFER]: AddressType.DEFERRED_TRANSFER, + [AccountType.NONE]: AddressType.NONE, } const addressToAccountMap: Record = Object.entries( @@ -66,7 +58,7 @@ export function toAddressType(input: AccountType | AddressType): AddressType { if (isAddressType(input)) { return input } - return accountToAddressMap[input as AccountType] ?? AddressType_NONE + return accountToAddressMap[input as AccountType] ?? AddressType.NONE } export function toAccountType(input: AccountType | AddressType): AccountType { From 832f2f6ce56b7543593fb3b1d771faad0ebd4b58 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 8 Sep 2025 14:34:00 +0200 Subject: [PATCH 031/226] update for hiero --- dlt-connector/log4js-config.json | 17 +++++++++++-- .../client/GradidoNode/GradidoNodeClient.ts | 2 +- .../src/client/backend/community.schema.ts | 3 +++ dlt-connector/src/client/hiero/HieroClient.ts | 24 ++++++++++++++++--- dlt-connector/src/config/index.ts | 2 +- dlt-connector/src/index.ts | 2 +- dlt-connector/src/schemas/base.schema.ts | 7 ------ dlt-connector/src/schemas/typeGuard.schema.ts | 4 ++-- 8 files changed, 44 insertions(+), 17 deletions(-) diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index a6a33686b..66127eb80 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -15,6 +15,19 @@ "fileNameSep" : "_", "numBackups" : 30 }, + "dlt.client.HieroClient": { + "type": "dateFile", + "filename": "../logs/dlt-connector/apiversion-%v.log", + "pattern": "yyyy-MM-dd", + "layout": + { + "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] [%f : %l] - %m" + }, + "compress": true, + "keepFileExt" : true, + "fileNameSep" : "_", + "numBackups" : 30 + }, "errorFile": { "type": "dateFile", @@ -22,7 +35,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" }, "compress": true, "keepFileExt" : true, @@ -40,7 +53,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{url}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" } } }, diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index 69609657e..5b58ad258 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -66,7 +66,7 @@ export class GradidoNodeClient { } const response = await this.rpcCall<{ transaction: string }>('gettransaction', parameter) if (response.isSuccess()) { - this.logger.debug('result: ', response.result.transaction) + // this.logger.debug('result: ', response.result.transaction) return parse(confirmedTransactionSchema, response.result.transaction) } if (response.isError()) { diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts index b74ac49cf..a37159bc5 100644 --- a/dlt-connector/src/client/backend/community.schema.ts +++ b/dlt-connector/src/client/backend/community.schema.ts @@ -8,6 +8,7 @@ import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' */ export const communitySchema = v.object({ uuid: uuidv4Schema, + name: v.string('expect string type'), hieroTopicId: v.nullish(hieroIdSchema), foreign: v.boolean('expect boolean type'), creationDate: dateSchema, @@ -21,6 +22,7 @@ export const homeCommunityGraphqlQuery = gql` query { homeCommunity { uuid + name hieroTopicId foreign creationDate @@ -32,6 +34,7 @@ export const setHomeCommunityTopicId = gql` mutation ($uuid: String!, $hieroTopicId: String){ updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { uuid + name hieroTopicId foreign creationDate diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index f63ac650a..c06eedf8b 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -2,6 +2,7 @@ import { AccountBalance, AccountBalanceQuery, Client, + Key, LocalProvider, PrivateKey, Timestamp, @@ -58,6 +59,7 @@ export class HieroClient { topicId: HieroId, transaction: GradidoTransaction, ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { + this.logger.addContext('topicId', topicId.toString()) const serializedTransaction = transaction.getSerializedTransaction() if (!serializedTransaction) { throw new Error('cannot serialize transaction') @@ -84,10 +86,16 @@ export class HieroClient { } public async getTopicInfo(topicId: HieroId): Promise { + this.logger.addContext('topicId', topicId.toString()) const info = await new TopicInfoQuery() .setTopicId(TopicId.fromString(topicId)) .execute(this.client) - this.logger.debug(JSON.stringify(info, null, 2)) + this.logger.info(`topic is valid until ${info.expirationTime?.toDate()?.toLocaleString()}`) + if (info.topicMemo) { + this.logger.info(`topic memo: ${info.topicMemo}`) + } + this.logger.debug(`topic sequence number: ${info.sequenceNumber.toNumber()}`) + // this.logger.debug(JSON.stringify(info, null, 2)) return parse(topicInfoSchema, { topicId: topicId.toString(), sequenceNumber: info.sequenceNumber.toNumber(), @@ -97,16 +105,26 @@ export class HieroClient { }) } - public async createTopic(): Promise { - let transaction = await new TopicCreateTransaction().freezeWithSigner(this.wallet) + public async createTopic(topicMemo?: string): Promise { + let transaction = new TopicCreateTransaction({ + topicMemo, + adminKey: undefined, + submitKey: undefined, + autoRenewPeriod: undefined, + autoRenewAccountId: undefined, + }) + + transaction = await transaction.freezeWithSigner(this.wallet) transaction = await transaction.signWithSigner(this.wallet) const createResponse = await transaction.executeWithSigner(this.wallet) const createReceipt = await createResponse.getReceiptWithSigner(this.wallet) this.logger.debug(createReceipt.toString()) + this.logger.addContext('topicId', createReceipt.topicId?.toString()) return parse(hieroIdSchema, createReceipt.topicId?.toString()) } public async updateTopic(topicId: HieroId): Promise { + this.logger.addContext('topicId', topicId.toString()) let transaction = new TopicUpdateTransaction() transaction.setExpirationTime(new Date(new Date().getTime() + MIN_AUTORENEW_PERIOD * 1000)) transaction.setTopicId(TopicId.fromString(topicId)) diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index d4184d9d6..164b78601 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -7,8 +7,8 @@ dotenv.config() type ConfigOutput = InferOutput let config: ConfigOutput -console.info('Config loading...') try { + console.info('Config loading...') config = parse(configSchema, process.env) } catch (error: Error | unknown) { if (error instanceof ValiError) { diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 733bbcfc0..cafd1a006 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -81,7 +81,7 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.hieroTopicId) { - const topicId = await hiero.createTopic() + const topicId = await hiero.createTopic(homeCommunity.name) // update topic on backend server homeCommunity = await backend.setHomeCommunityTopicId(homeCommunity.uuid, topicId) } else { diff --git a/dlt-connector/src/schemas/base.schema.ts b/dlt-connector/src/schemas/base.schema.ts index 2e065f55d..da3dbfdfa 100644 --- a/dlt-connector/src/schemas/base.schema.ts +++ b/dlt-connector/src/schemas/base.schema.ts @@ -1,9 +1,2 @@ import { MemoryBlock } from 'gradido-blockchain-js' import * as v from 'valibot' - -export const keyGenerationSeedSchema = v.pipe( - v.string('expect string type'), - v.hexadecimal('expect hexadecimal string'), - v.length(64, 'expect seed length minimum 64 characters (32 Bytes)'), - v.transform((input: string) => MemoryBlock.fromHex(input)), -) diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts index bddb7048f..b084e8531 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -128,8 +128,8 @@ declare const validHieroTransactionId: unique symbol export type HieroTransactionId = string & { [validHieroTransactionId]: true } export const hieroTransactionIdSchema = v.pipe( - v.string('expect hiero transaction id type, for example 0.0.141760-1755138896-607329203'), - v.regex(/^[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-[0-9]+$/), + v.string('expect hiero transaction id type, for example 0.0.141760-1755138896-607329203 or 0.0.141760@1755138896.607329203'), + v.regex(/^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+-[0-9]+|@[0-9]+\.[0-9]+)$/), v.transform((input: string) => input as HieroTransactionId), ) From eb3bf5e9049bd65c11773b82324d500def3d15cb Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 16 Sep 2025 07:13:02 +0200 Subject: [PATCH 032/226] update with hiero changes and other changes --- .../dltConnector/DltConnectorClient.test.ts | 125 ------------ .../apis/dltConnector/DltConnectorClient.ts | 52 ++--- .../__mocks__/DltConnectorClient.ts | 55 ++++++ .../AbstractTransactionToDlt.role.ts | 3 +- .../TransactionLinkDeleteToDlt.role.ts | 20 +- .../TransactionLinkToDlt.role.ts | 20 +- .../transactionToDlt/TransactionToDlt.role.ts | 2 +- .../transactionToDlt/UserToDlt.role.ts | 15 +- .../transactionToDlt.context.ts | 29 +-- .../dltConnector/model/AccountIdentifier.ts | 17 ++ .../model/CommunityAccountIdentifier.ts | 10 + .../apis/dltConnector/model/CommunityUser.ts | 10 - .../dltConnector/model/TransactionDraft.ts | 6 +- .../dltConnector/model/TransactionError.ts | 7 - .../dltConnector/model/TransactionRecipe.ts | 7 - .../dltConnector/model/TransactionResult.ts | 8 - .../apis/dltConnector/model/UserIdentifier.ts | 17 -- .../sendTransactionsToDltConnector.test.ts | 81 +------- .../sendTransactionsToDltConnector.ts | 2 +- bun.lock | 8 +- .../DltTransaction.ts | 36 ---- .../0088-add_dlt_users_table/DltUser.ts | 37 ---- .../entity/0088-add_dlt_users_table/User.ts | 182 ----------------- .../0089-merge_dlt_tables/DltTransaction.ts | 55 ------ .../0089-merge_dlt_tables/Transaction.ts | 176 ----------------- .../0089-merge_dlt_tables/TransactionLink.ts | 85 -------- database/entity/0089-merge_dlt_tables/User.ts | 186 ------------------ database/entity/DltTransaction.ts | 1 - database/entity/Transaction.ts | 1 - database/entity/TransactionLink.ts | 1 - database/entity/User.ts | 1 - dlt-connector/src/client/hiero/HieroClient.ts | 6 + dlt-connector/src/index.ts | 5 +- .../sendToHiero/SendToHiero.context.ts | 10 +- dlt-connector/src/server/index.ts | 27 ++- yarn.lock | 5 + 36 files changed, 208 insertions(+), 1100 deletions(-) create mode 100644 backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts create mode 100644 backend/src/apis/dltConnector/model/AccountIdentifier.ts create mode 100644 backend/src/apis/dltConnector/model/CommunityAccountIdentifier.ts delete mode 100644 backend/src/apis/dltConnector/model/CommunityUser.ts delete mode 100644 backend/src/apis/dltConnector/model/TransactionError.ts delete mode 100644 backend/src/apis/dltConnector/model/TransactionRecipe.ts delete mode 100644 backend/src/apis/dltConnector/model/TransactionResult.ts delete mode 100644 backend/src/apis/dltConnector/model/UserIdentifier.ts delete mode 100644 database/entity/0088-add_dlt_users_table/DltTransaction.ts delete mode 100644 database/entity/0088-add_dlt_users_table/DltUser.ts delete mode 100644 database/entity/0088-add_dlt_users_table/User.ts delete mode 100644 database/entity/0089-merge_dlt_tables/DltTransaction.ts delete mode 100644 database/entity/0089-merge_dlt_tables/Transaction.ts delete mode 100644 database/entity/0089-merge_dlt_tables/TransactionLink.ts delete mode 100644 database/entity/0089-merge_dlt_tables/User.ts delete mode 100644 database/entity/DltTransaction.ts delete mode 100644 database/entity/Transaction.ts delete mode 100644 database/entity/TransactionLink.ts delete mode 100644 database/entity/User.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index 00b15348d..0e2043a09 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -1,46 +1,7 @@ -import { Transaction as DbTransaction } from 'database' -import { Decimal } from 'decimal.js-light' -import { DataSource } from 'typeorm' - -import { cleanDB, testEnvironment } from '@test/helpers' - import { CONFIG } from '@/config' -import { LogError } from '@/server/LogError' import { DltConnectorClient } from './DltConnectorClient' -let con: DataSource - -let testEnv: { - con: DataSource -} - -// Mock the GraphQLClient -jest.mock('graphql-request', () => { - const originalModule = jest.requireActual('graphql-request') - - return { - __esModule: true, - ...originalModule, - GraphQLClient: jest.fn().mockImplementation((url: string) => { - if (url === 'invalid') { - throw new Error('invalid url') - } - return { - // why not using mockResolvedValueOnce or mockReturnValueOnce? - // I have tried, but it didn't work and return every time the first value - request: jest.fn().mockImplementation(() => { - return Promise.resolve({ - transmitTransaction: { - succeed: true, - }, - }) - }), - } - }), - } -}) - describe('undefined DltConnectorClient', () => { it('invalid url', () => { CONFIG.DLT_CONNECTOR_URL = 'invalid' @@ -58,90 +19,4 @@ describe('undefined DltConnectorClient', () => { }) }) -/* -describe.skip('transmitTransaction, without db connection', () => { - const transaction = new DbTransaction() - transaction.typeId = 2 // Example transaction type ID - transaction.amount = new Decimal('10.00') // Example amount - transaction.balanceDate = new Date() // Example creation date - transaction.id = 1 // Example transaction ID - it('cannot query for transaction id', async () => { - const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction) - expect(result).toBe(false) - }) -}) -*/ - -describe('transmitTransaction', () => { - beforeAll(async () => { - testEnv = await testEnvironment() - con = testEnv.con - await cleanDB() - }) - - afterAll(async () => { - await cleanDB() - await con.destroy() - }) - - const transaction = new DbTransaction() - transaction.typeId = 2 // Example transaction type ID - transaction.amount = new Decimal('10.00') // Example amount - transaction.balanceDate = new Date() // Example creation date - transaction.id = 1 // Example transaction ID - - // data needed to let save succeed - transaction.memo = "I'm a dummy memo" - transaction.userId = 1 - transaction.userGradidoID = 'dummy gradido id' - - /* - it.skip('cannot find transaction in db', async () => { - const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction) - expect(result).toBe(false) - }) - */ - - it('invalid transaction type', async () => { - const localTransaction = new DbTransaction() - localTransaction.typeId = 12 - try { - await DltConnectorClient.getInstance()?.transmitTransaction(localTransaction) - } catch (e) { - expect(e).toMatchObject( - new LogError(`invalid transaction type id: ${localTransaction.typeId.toString()}`), - ) - } - }) - - /* - it.skip('should transmit the transaction and update the dltTransactionId in the database', async () => { - await transaction.save() - - const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction) - expect(result).toBe(true) - }) - - it.skip('invalid dltTransactionId (maximal 32 Bytes in Binary)', async () => { - await transaction.save() - - const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction) - expect(result).toBe(false) - }) - */ -}) - -/* -describe.skip('try transmitTransaction but graphql request failed', () => { - it('graphql request should throw', async () => { - const transaction = new DbTransaction() - transaction.typeId = 2 // Example transaction type ID - transaction.amount = new Decimal('10.00') // Example amount - transaction.balanceDate = new Date() // Example creation date - transaction.id = 1 // Example transaction ID - const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction) - expect(result).toBe(false) - }) -}) -*/ diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 4fef742ed..16c74ab0c 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -3,29 +3,10 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLogger } from 'log4js' import { TransactionDraft } from './model/TransactionDraft' -import { TransactionResult } from './model/TransactionResult' -import { GraphQLClient } from 'graphql-request' -import { gql } from 'graphql-request' +import { IRestResponse, RestClient } from 'typed-rest-client' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector`) -const sendTransaction = gql` - mutation ($input: TransactionDraft!) { - sendTransaction(data: $input) { - error { - message - name - } - succeed - recipe { - createdAt - type - messageIdHex - } - } - } -` - // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts /** @@ -35,7 +16,7 @@ const sendTransaction = gql` export class DltConnectorClient { private static instance: DltConnectorClient - client: GraphQLClient + client: RestClient /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. @@ -59,16 +40,12 @@ export class DltConnectorClient { } if (!DltConnectorClient.instance.client) { try { - DltConnectorClient.instance.client = new GraphQLClient(CONFIG.DLT_CONNECTOR_URL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - jsonSerializer: { - parse: JSON.parse, - stringify: JSON.stringify, - }, - }) + DltConnectorClient.instance.client = new RestClient( + 'gradido-backend', + CONFIG.DLT_CONNECTOR_URL, + undefined, + { keepAlive: true } + ) } catch (e) { logger.error("couldn't connect to dlt-connector: ", e) return @@ -78,16 +55,11 @@ export class DltConnectorClient { } /** - * transmit transaction via dlt-connector to iota - * and update dltTransactionId of transaction in db with iota message id + * transmit transaction via dlt-connector to hiero + * and update dltTransactionId of transaction in db with hiero transaction id */ - public async sendTransaction(input: TransactionDraft): Promise { + public async sendTransaction(input: TransactionDraft): Promise> { logger.debug('transmit transaction or user to dlt connector', input) - const { - data: { sendTransaction: result }, - } = await this.client.rawRequest<{ sendTransaction: TransactionResult }>(sendTransaction, { - input, - }) - return result + return await this.client.create('/sendTransaction', input) } } diff --git a/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts b/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts new file mode 100644 index 000000000..81a7c5398 --- /dev/null +++ b/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts @@ -0,0 +1,55 @@ +import { CONFIG } from '@/config' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' +import { getLogger } from 'log4js' + +import { TransactionDraft } from '@/apis/dltConnector/model/TransactionDraft' +import { IRestResponse } from 'typed-rest-client' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector`) + +// Source: https://refactoring.guru/design-patterns/singleton/typescript/example +// and ../federation/client/FederationClientFactory.ts +/** + * A Singleton class defines the `getInstance` method that lets clients access + * the unique singleton instance. + */ + +export class DltConnectorClient { + private static instance: DltConnectorClient + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + + private constructor() {} + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(): DltConnectorClient | undefined { + if (!CONFIG.DLT_CONNECTOR || !CONFIG.DLT_CONNECTOR_URL) { + logger.info(`dlt-connector are disabled via config...`) + return + } + if (!DltConnectorClient.instance) { + DltConnectorClient.instance = new DltConnectorClient() + } + return DltConnectorClient.instance + } + + /** + * transmit transaction via dlt-connector to hiero + * and update dltTransactionId of transaction in db with hiero transaction id + */ + public async sendTransaction(input: TransactionDraft): Promise> { + logger.debug('transmit transaction or user to dlt connector', input) + return Promise.resolve({ + statusCode: 200, + result: 'test', + headers: {}, + }) + } +} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts index 5e756fb7d..22f7104b2 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts @@ -3,8 +3,7 @@ import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from 'typeorm' import { DltTransaction } from 'database' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' +import { Logger } from 'log4js' export abstract class AbstractTransactionToDltRole { protected self: T | null diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts index b8eaa633a..d4964a9f8 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts @@ -2,14 +2,14 @@ import { DltTransaction, TransactionLink } from 'database' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' -import { CommunityUser } from '@dltConnector/model/CommunityUser' import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { UserIdentifier } from '@dltConnector/model/UserIdentifier' +import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier' import { LogError } from '@/server/LogError' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' +import { CommunityAccountIdentifier } from '@dltConnector/model/CommunityAccountIdentifier' /** * redeem deferred transfer transaction by creator, so "deleting" it @@ -17,7 +17,10 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole { async initWithLast(): Promise { const queryBuilder = this.createQueryForPendingItems( - TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'), + TransactionLink + .createQueryBuilder() + .leftJoinAndSelect('TransactionLink.user', 'user') + .leftJoinAndSelect('user.community', 'community'), 'TransactionLink.id = dltTransaction.transactionLinkId and dltTransaction.type_id <> 4', // eslint-disable-next-line camelcase { TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }, @@ -67,8 +70,15 @@ export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole const draft = new TransactionDraft() draft.amount = this.self.amount.abs().toString() const user = this.self.user - draft.user = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code)) - draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID, 1)) + if (!user.community) { + throw new LogError(`missing community for user ${user.id}`) + } + const topicId = user.community.hieroTopicId + if (!topicId) { + throw new LogError(`missing topicId for community ${user.community.id}`) + } + draft.user = new AccountIdentifier(topicId, new IdentifierSeed(this.self.code)) + draft.linkedUser = new AccountIdentifier(topicId, new CommunityAccountIdentifier(user.gradidoID)) draft.createdAt = this.self.deletedAt.toISOString() draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER return draft diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts index 3d2717301..05f9d319e 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts @@ -2,14 +2,14 @@ import { DltTransaction, TransactionLink } from 'database' import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' import { TransactionType } from '@dltConnector/enum/TransactionType' -import { CommunityUser } from '@dltConnector/model/CommunityUser' import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { UserIdentifier } from '@dltConnector/model/UserIdentifier' +import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier' import { LogError } from '@/server/LogError' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' +import { CommunityAccountIdentifier } from '../../model/CommunityAccountIdentifier' /** * send transactionLink as Deferred Transfers @@ -17,7 +17,10 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { async initWithLast(): Promise { this.self = await this.createQueryForPendingItems( - TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'), + TransactionLink + .createQueryBuilder() + .leftJoinAndSelect('TransactionLink.user', 'user') + .leftJoinAndSelect('user.community', 'community'), 'TransactionLink.id = dltTransaction.transactionLinkId', // eslint-disable-next-line camelcase { TransactionLink_createdAt: 'ASC', User_id: 'ASC' }, @@ -39,8 +42,15 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { async initWithLast(): Promise { this.self = await this.createQueryForPendingItems( - User.createQueryBuilder(), + User.createQueryBuilder().leftJoinAndSelect('User.community', 'community'), 'User.id = dltTransaction.userId', // eslint-disable-next-line camelcase { User_created_at: 'ASC', User_id: 'ASC' }, @@ -36,8 +36,15 @@ export class UserToDltRole extends AbstractTransactionToDltRole { if (!this.self) { throw new LogError('try to create dlt entry for empty transaction') } + if (!this.self.community) { + throw new LogError(`missing community for user ${this.self.id}`) + } + const topicId = this.self.community.hieroTopicId + if (!topicId) { + throw new LogError(`missing topicId for community ${this.self.community.id}`) + } const draft = new TransactionDraft() - draft.user = new UserIdentifier(this.self.communityUuid, new CommunityUser(this.self.gradidoID)) + draft.user = new AccountIdentifier(topicId, new CommunityAccountIdentifier(this.self.gradidoID)) draft.createdAt = this.self.createdAt.toISOString() draft.accountType = AccountType.COMMUNITY_HUMAN draft.type = TransactionType.REGISTER_ADDRESS diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts index b03bd5300..cb1d8cca2 100644 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts @@ -1,14 +1,13 @@ import { Transaction, TransactionLink, User } from 'database' import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' -import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult' import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role' import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' import { TransactionToDltRole } from './TransactionToDlt.role' import { UserToDltRole } from './UserToDlt.role' -import { getLogger } from 'log4js' +import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' /** @@ -16,10 +15,9 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' * Context for sending transactions to dlt connector, always the oldest not sended transaction first */ export async function transactionToDlt(dltConnector: DltConnectorClient): Promise { - async function findNextPendingTransaction(): Promise< + async function findNextPendingTransaction(logger: Logger): Promise< AbstractTransactionToDltRole > { - const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/interaction/transactionToDlt`) // collect each oldest not sended entity from db and choose oldest const results = await Promise.all([ new TransactionToDltRole(logger).initWithLast(), @@ -34,18 +32,28 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis }) return results[0] } + + const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.interaction.transactionToDlt`) while (true) { - const pendingTransactionRole = await findNextPendingTransaction() + const pendingTransactionRole = await findNextPendingTransaction(logger) const pendingTransaction = pendingTransactionRole.getEntity() if (!pendingTransaction) { break } let messageId = '' let error: string | null = null - let result: TransactionResult | undefined try { - result = await dltConnector.sendTransaction(pendingTransactionRole.convertToGraphqlInput()) + const result = await dltConnector.sendTransaction( + pendingTransactionRole.convertToGraphqlInput() + ) + if (result.statusCode === 200 && result.result) { + messageId = result.result + } else { + error = `empty result with status code ${result.statusCode}` + logger.error('error from dlt-connector', result) + } } catch (e) { + logger.debug(e) if (e instanceof Error) { error = e.message } else if (typeof e === 'string') { @@ -54,13 +62,6 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis throw e } } - if (result?.succeed && result.recipe) { - messageId = result.recipe.messageIdHex - } else if (result?.error) { - error = result.error.message - logger.error('error from dlt-connector', result.error) - } - await pendingTransactionRole.saveTransactionResult(messageId, error) } } diff --git a/backend/src/apis/dltConnector/model/AccountIdentifier.ts b/backend/src/apis/dltConnector/model/AccountIdentifier.ts new file mode 100644 index 000000000..ed1d61e51 --- /dev/null +++ b/backend/src/apis/dltConnector/model/AccountIdentifier.ts @@ -0,0 +1,17 @@ +import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' +import { IdentifierSeed } from './IdentifierSeed' + +export class AccountIdentifier { + communityTopicId: string + account?: CommunityAccountIdentifier + seed?: IdentifierSeed // used for deferred transfers + + constructor(communityTopicId: string, input: CommunityAccountIdentifier | IdentifierSeed) { + if (input instanceof CommunityAccountIdentifier) { + this.account = input + } else if (input instanceof IdentifierSeed) { + this.seed = input + } + this.communityTopicId = communityTopicId + } +} diff --git a/backend/src/apis/dltConnector/model/CommunityAccountIdentifier.ts b/backend/src/apis/dltConnector/model/CommunityAccountIdentifier.ts new file mode 100644 index 000000000..1e8b6a64f --- /dev/null +++ b/backend/src/apis/dltConnector/model/CommunityAccountIdentifier.ts @@ -0,0 +1,10 @@ +export class CommunityAccountIdentifier { + // for community user, uuid and communityUuid used + userUuid: string + accountNr?: number + + constructor(userUuid: string, accountNr?: number) { + this.userUuid = userUuid + this.accountNr = accountNr + } +} diff --git a/backend/src/apis/dltConnector/model/CommunityUser.ts b/backend/src/apis/dltConnector/model/CommunityUser.ts deleted file mode 100644 index 0a4eadebf..000000000 --- a/backend/src/apis/dltConnector/model/CommunityUser.ts +++ /dev/null @@ -1,10 +0,0 @@ -export class CommunityUser { - // for community user, uuid and communityUuid used - uuid: string - accountNr?: number - - constructor(uuid: string, accountNr?: number) { - this.uuid = uuid - this.accountNr = accountNr - } -} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index d197fe629..8dba79bdc 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -2,12 +2,12 @@ import { AccountType } from '@dltConnector/enum/AccountType' import { TransactionType } from '@dltConnector/enum/TransactionType' -import { UserIdentifier } from './UserIdentifier' +import { AccountIdentifier } from './AccountIdentifier' export class TransactionDraft { - user: UserIdentifier + user: AccountIdentifier // not used for simply register address - linkedUser?: UserIdentifier + linkedUser?: AccountIdentifier // not used for register address amount?: string memo?: string diff --git a/backend/src/apis/dltConnector/model/TransactionError.ts b/backend/src/apis/dltConnector/model/TransactionError.ts deleted file mode 100644 index a2b1348a5..000000000 --- a/backend/src/apis/dltConnector/model/TransactionError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { TransactionErrorType } from '@dltConnector/enum/TransactionErrorType' - -export interface TransactionError { - type: TransactionErrorType - message: string - name: string -} diff --git a/backend/src/apis/dltConnector/model/TransactionRecipe.ts b/backend/src/apis/dltConnector/model/TransactionRecipe.ts deleted file mode 100644 index 504ff2044..000000000 --- a/backend/src/apis/dltConnector/model/TransactionRecipe.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { TransactionType } from '@dltConnector/enum/TransactionType' - -export interface TransactionRecipe { - createdAt: string - type: TransactionType - messageIdHex: string -} diff --git a/backend/src/apis/dltConnector/model/TransactionResult.ts b/backend/src/apis/dltConnector/model/TransactionResult.ts deleted file mode 100644 index 510907429..000000000 --- a/backend/src/apis/dltConnector/model/TransactionResult.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { TransactionError } from './TransactionError' -import { TransactionRecipe } from './TransactionRecipe' - -export interface TransactionResult { - error?: TransactionError - recipe?: TransactionRecipe - succeed: boolean -} diff --git a/backend/src/apis/dltConnector/model/UserIdentifier.ts b/backend/src/apis/dltConnector/model/UserIdentifier.ts deleted file mode 100644 index 059405bd0..000000000 --- a/backend/src/apis/dltConnector/model/UserIdentifier.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CommunityUser } from './CommunityUser' -import { IdentifierSeed } from './IdentifierSeed' - -export class UserIdentifier { - communityUuid: string - communityUser?: CommunityUser - seed?: IdentifierSeed // used for deferred transfers - - constructor(communityUuid: string, input: CommunityUser | IdentifierSeed) { - if (input instanceof CommunityUser) { - this.communityUser = input - } else if (input instanceof IdentifierSeed) { - this.seed = input - } - this.communityUuid = communityUuid - } -} diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts index b5ec0a08a..50af15e9a 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts @@ -1,9 +1,5 @@ -import { ApolloServerTestClient } from 'apollo-server-testing' import { Community, DltTransaction, Transaction } from 'database' import { Decimal } from 'decimal.js-light' -// import { GraphQLClient } from 'graphql-request' -// import { Response } from 'graphql-request/dist/types' -import { GraphQLClient } from 'graphql-request' import { Response } from 'graphql-request/dist/types' import { DataSource } from 'typeorm' import { v4 as uuidv4 } from 'uuid' @@ -15,11 +11,11 @@ import { CONFIG } from '@/config' import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { creations } from '@/seeds/creation' import { creationFactory } from '@/seeds/factory/creation' -import { userFactory } from '@/seeds/factory/user' -import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { bobBaumeister } from '@/seeds/users/bob-baumeister' -import { peterLustig } from '@/seeds/users/peter-lustig' -import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' +import { userFactory } from 'database/src/seeds/factory/user' +import { bibiBloxberg } from 'database/src/seeds/users/bibi-bloxberg' +import { bobBaumeister } from 'database/src/seeds/users/bob-baumeister' +import { peterLustig } from 'database/src/seeds/users/peter-lustig' +import { raeuberHotzenplotz } from 'database/src/seeds/users/raeuber-hotzenplotz' import { getLogger } from 'config-schema/test/testSetup' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' @@ -31,63 +27,6 @@ const logger = getLogger( `${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.sendTransactionsToDltConnector`, ) -/* -// Mock the GraphQLClient -jest.mock('graphql-request', () => { - const originalModule = jest.requireActual('graphql-request') - - let testCursor = 0 - - return { - __esModule: true, - ...originalModule, - GraphQLClient: jest.fn().mockImplementation((url: string) => { - if (url === 'invalid') { - throw new Error('invalid url') - } - return { - // why not using mockResolvedValueOnce or mockReturnValueOnce? - // I have tried, but it didn't work and return every time the first value - request: jest.fn().mockImplementation(() => { - testCursor++ - if (testCursor === 4) { - return Promise.resolve( - // invalid, is 33 Bytes long as binary - { - transmitTransaction: { - dltTransactionIdHex: - '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516212A', - }, - }, - ) - } else if (testCursor === 5) { - throw Error('Connection error') - } else { - return Promise.resolve( - // valid, is 32 Bytes long as binary - { - transmitTransaction: { - dltTransactionIdHex: - '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc51621', - }, - }, - ) - } - }), - } - }), - } -}) -let mutate: ApolloServerTestClient['mutate'], - query: ApolloServerTestClient['query'], - con: Connection -let testEnv: { - mutate: ApolloServerTestClient['mutate'] - query: ApolloServerTestClient['query'] - con: Connection -} -*/ - async function createHomeCommunity(): Promise { const homeCommunity = Community.create() homeCommunity.foreign = false @@ -336,8 +275,6 @@ async function createTxReceive1FromSend3(verified: boolean): Promise { CONFIG.DLT_CONNECTOR = true - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - return { - data: { - sendTransaction: { succeed: true }, - }, - } as Response - }) - await sendTransactionsToDltConnector() expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts index 3b0bfbc27..ef58ed606 100644 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts @@ -16,7 +16,7 @@ import { transactionToDlt } from './interaction/transactionToDlt/transactionToDl import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/sendTransactionsToDltConnector`) +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.sendTransactionsToDltConnector`) let isLoopRunning = true diff --git a/bun.lock b/bun.lock index b49609f5c..532b20dc6 100644 --- a/bun.lock +++ b/bun.lock @@ -113,10 +113,10 @@ "await-semaphore": "^0.1.3", "axios": "^0.21.1", "class-validator": "^0.13.1", - "config-schema": "workspace:*", - "core": "workspace:*", + "config-schema": "*", + "core": "*", "cors": "^2.8.5", - "database": "workspace:*", + "database": "*", "decimal.js-light": "^2.5.1", "dotenv": "^10.0.0", "esbuild": "^0.25.2", @@ -146,7 +146,7 @@ "random-bigint": "^0.0.1", "reflect-metadata": "^0.1.13", "regenerator-runtime": "^0.14.1", - "shared": "workspace:*", + "shared": "*", "source-map-support": "^0.5.21", "ts-jest": "29.4.0", "ts-node": "^10.9.2", diff --git a/database/entity/0088-add_dlt_users_table/DltTransaction.ts b/database/entity/0088-add_dlt_users_table/DltTransaction.ts deleted file mode 100644 index 653077bac..000000000 --- a/database/entity/0088-add_dlt_users_table/DltTransaction.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' -import { Transaction } from '../Transaction' - -@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class DltTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: false }) - transactionId: number - - @Column({ - name: 'message_id', - length: 64, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - messageId: string - - @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) - verified: boolean - - @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) - createdAt: Date - - @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) - verifiedAt: Date | null - - @Column({ name: 'error', type: 'text', nullable: true }) - error: string | null - - @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) - @JoinColumn({ name: 'transaction_id' }) - transaction?: Transaction | null -} diff --git a/database/entity/0088-add_dlt_users_table/DltUser.ts b/database/entity/0088-add_dlt_users_table/DltUser.ts deleted file mode 100644 index 2b9dccb3f..000000000 --- a/database/entity/0088-add_dlt_users_table/DltUser.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' -// this Entity was removed in current code and isn't any longer compatible with user -import { User } from './User' - -@Entity('dlt_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class DltUser extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) - userId: number - - @Column({ - name: 'message_id', - length: 64, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - messageId: string - - @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) - verified: boolean - - @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) - createdAt: Date - - @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) - verifiedAt: Date | null - - @Column({ name: 'error', type: 'text', nullable: true }) - error: string | null - - @OneToOne(() => User, (user) => user.dltUser) - @JoinColumn({ name: 'user_id' }) - user?: User | null -} diff --git a/database/entity/0088-add_dlt_users_table/User.ts b/database/entity/0088-add_dlt_users_table/User.ts deleted file mode 100644 index f9b079a04..000000000 --- a/database/entity/0088-add_dlt_users_table/User.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { - BaseEntity, - Entity, - PrimaryGeneratedColumn, - Column, - DeleteDateColumn, - OneToMany, - JoinColumn, - OneToOne, - Geometry, - ManyToOne, -} from 'typeorm' -import { Contribution } from '../Contribution' -import { ContributionMessage } from '../ContributionMessage' -import { UserContact } from '../UserContact' -import { UserRole } from '../UserRole' -import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' -import { Community } from '../Community' -// removed in current version -import { DltUser } from './DltUser' - -@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class User extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ type: 'bool', default: false }) - foreign: boolean - - @Column({ - name: 'gradido_id', - length: 36, - nullable: false, - collation: 'utf8mb4_unicode_ci', - }) - gradidoID: string - - @Column({ - name: 'community_uuid', - type: 'char', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - communityUuid: string - - @ManyToOne(() => Community, (community) => community.users) - @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) - community: Community | null - - @Column({ - name: 'alias', - length: 20, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - alias: string - - @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) - @JoinColumn({ name: 'email_id' }) - emailContact: UserContact - - @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) - emailId: number | null - - @Column({ - name: 'first_name', - length: 255, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - firstName: string - - @Column({ - name: 'last_name', - length: 255, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - lastName: string - - @Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) - gmsPublishName: number - - @Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) - humhubPublishName: number - - @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) - createdAt: Date - - @DeleteDateColumn({ name: 'deleted_at', nullable: true }) - deletedAt: Date | null - - @Column({ type: 'bigint', default: 0, unsigned: true }) - password: BigInt - - @Column({ - name: 'password_encryption_type', - type: 'int', - unsigned: true, - nullable: false, - default: 0, - }) - passwordEncryptionType: number - - @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) - language: string - - @Column({ type: 'bool', default: false }) - hideAmountGDD: boolean - - @Column({ type: 'bool', default: false }) - hideAmountGDT: boolean - - @OneToMany(() => UserRole, (userRole) => userRole.user) - @JoinColumn({ name: 'user_id' }) - userRoles: UserRole[] - - @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) - referrerId?: number | null - - @Column({ - name: 'contribution_link_id', - type: 'int', - unsigned: true, - nullable: true, - default: null, - }) - contributionLinkId?: number | null - - @Column({ name: 'publisher_id', default: 0 }) - publisherId: number - - @Column({ name: 'gms_allowed', type: 'bool', default: true }) - gmsAllowed: boolean - - @Column({ - name: 'location', - type: 'geometry', - default: null, - nullable: true, - transformer: GeometryTransformer, - }) - location: Geometry | null - - @Column({ - name: 'gms_publish_location', - type: 'int', - unsigned: true, - nullable: false, - default: 2, - }) - gmsPublishLocation: number - - @Column({ name: 'gms_registered', type: 'bool', default: false }) - gmsRegistered: boolean - - @Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true }) - gmsRegisteredAt: Date | null - - @Column({ name: 'humhub_allowed', type: 'bool', default: false }) - humhubAllowed: boolean - - @OneToMany(() => Contribution, (contribution) => contribution.user) - @JoinColumn({ name: 'user_id' }) - contributions?: Contribution[] - - @OneToMany(() => ContributionMessage, (message) => message.user) - @JoinColumn({ name: 'user_id' }) - messages?: ContributionMessage[] - - @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) - @JoinColumn({ name: 'user_id' }) - userContacts?: UserContact[] - - @OneToOne(() => DltUser, (dlt) => dlt.userId) - @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) - dltUser?: DltUser | null -} diff --git a/database/entity/0089-merge_dlt_tables/DltTransaction.ts b/database/entity/0089-merge_dlt_tables/DltTransaction.ts deleted file mode 100644 index 012bddf0b..000000000 --- a/database/entity/0089-merge_dlt_tables/DltTransaction.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' -import { Transaction } from '../Transaction' -import { User } from '../User' -import { TransactionLink } from '../TransactionLink' - -@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class DltTransaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: true }) - transactionId?: number | null - - @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true }) - userId?: number | null - - @Column({ name: 'transaction_link_id', type: 'int', unsigned: true, nullable: true }) - transactionLinkId?: number | null - - @Column({ name: 'type_id', unsigned: true, nullable: false }) - typeId: number - - @Column({ - name: 'message_id', - length: 64, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - messageId: string - - @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) - verified: boolean - - @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) - createdAt: Date - - @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) - verifiedAt: Date | null - - @Column({ name: 'error', type: 'text', nullable: true }) - error: string | null - - @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) - @JoinColumn({ name: 'transaction_id' }) - transaction?: Transaction | null - - @OneToOne(() => User, (user) => user.dltTransaction) - @JoinColumn({ name: 'user_id' }) - user?: User | null - - @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.dltTransaction) - @JoinColumn({ name: 'transaction_link_id' }) - transactionLink?: TransactionLink | null -} diff --git a/database/entity/0089-merge_dlt_tables/Transaction.ts b/database/entity/0089-merge_dlt_tables/Transaction.ts deleted file mode 100644 index 8eec4e1a9..000000000 --- a/database/entity/0089-merge_dlt_tables/Transaction.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* eslint-disable no-use-before-define */ -import { Decimal } from 'decimal.js-light' -import { - BaseEntity, - Entity, - PrimaryGeneratedColumn, - Column, - OneToOne, - JoinColumn, - ManyToOne, -} from 'typeorm' -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { Contribution } from '../Contribution' -import { DltTransaction } from '../DltTransaction' -import { TransactionLink } from '../TransactionLink' - -@Entity('transactions') -export class Transaction extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ type: 'int', unsigned: true, unique: true, nullable: true, default: null }) - previous: number | null - - @Column({ name: 'type_id', unsigned: true, nullable: false }) - typeId: number - - @Column({ - name: 'transaction_link_id', - type: 'int', - unsigned: true, - nullable: true, - default: null, - }) - transactionLinkId?: number | null - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - transformer: DecimalTransformer, - }) - amount: Decimal - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - transformer: DecimalTransformer, - }) - balance: Decimal - - @Column({ - name: 'balance_date', - type: 'datetime', - default: () => 'CURRENT_TIMESTAMP', - nullable: false, - }) - balanceDate: Date - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - transformer: DecimalTransformer, - }) - decay: Decimal - - @Column({ - name: 'decay_start', - type: 'datetime', - nullable: true, - default: null, - }) - decayStart: Date | null - - @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) - memo: string - - @Column({ name: 'creation_date', type: 'datetime', nullable: true, default: null }) - creationDate: Date | null - - @Column({ name: 'user_id', unsigned: true, nullable: false }) - userId: number - - @Column({ - name: 'user_community_uuid', - type: 'varchar', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - userCommunityUuid: string | null - - @Column({ - name: 'user_gradido_id', - type: 'varchar', - length: 36, - nullable: false, - collation: 'utf8mb4_unicode_ci', - }) - userGradidoID: string - - @Column({ - name: 'user_name', - type: 'varchar', - length: 512, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - userName: string | null - - @Column({ - name: 'linked_user_id', - type: 'int', - unsigned: true, - nullable: true, - default: null, - }) - linkedUserId?: number | null - - @Column({ - name: 'linked_user_community_uuid', - type: 'varchar', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - linkedUserCommunityUuid: string | null - - @Column({ - name: 'linked_user_gradido_id', - type: 'varchar', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - linkedUserGradidoID: string | null - - @Column({ - name: 'linked_user_name', - type: 'varchar', - length: 512, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - linkedUserName: string | null - - @Column({ - name: 'linked_transaction_id', - type: 'int', - unsigned: true, - nullable: true, - default: null, - }) - linkedTransactionId?: number | null - - @OneToOne(() => Contribution, (contribution) => contribution.transaction) - @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) - contribution?: Contribution | null - - @OneToOne(() => DltTransaction, (dlt) => dlt.transactionId) - @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) - dltTransaction?: DltTransaction | null - - @OneToOne(() => Transaction) - @JoinColumn({ name: 'previous' }) - previousTransaction?: Transaction | null - - @ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions) - @JoinColumn({ name: 'transaction_link_id' }) - transactionLink?: TransactionLink | null -} diff --git a/database/entity/0089-merge_dlt_tables/TransactionLink.ts b/database/entity/0089-merge_dlt_tables/TransactionLink.ts deleted file mode 100644 index 18bcf9892..000000000 --- a/database/entity/0089-merge_dlt_tables/TransactionLink.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Decimal } from 'decimal.js-light' -import { - BaseEntity, - Entity, - PrimaryGeneratedColumn, - Column, - DeleteDateColumn, - OneToOne, - JoinColumn, - OneToMany, -} from 'typeorm' -import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' -import { DltTransaction } from '../DltTransaction' -import { User } from '../User' -import { Transaction } from '../Transaction' - -@Entity('transaction_links') -export class TransactionLink extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ unsigned: true, nullable: false }) - userId: number - - @Column({ - type: 'decimal', - precision: 40, - scale: 20, - nullable: false, - transformer: DecimalTransformer, - }) - amount: Decimal - - @Column({ - type: 'decimal', - name: 'hold_available_amount', - precision: 40, - scale: 20, - nullable: false, - transformer: DecimalTransformer, - }) - holdAvailableAmount: Decimal - - @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) - memo: string - - @Column({ length: 24, nullable: false, collation: 'utf8mb4_unicode_ci' }) - code: string - - @Column({ - type: 'datetime', - nullable: false, - }) - createdAt: Date - - @DeleteDateColumn() - deletedAt: Date | null - - @Column({ - type: 'datetime', - nullable: false, - }) - validUntil: Date - - @Column({ - type: 'datetime', - nullable: true, - }) - redeemedAt: Date | null - - @Column({ type: 'int', unsigned: true, nullable: true }) - redeemedBy: number | null - - @OneToOne(() => DltTransaction, (dlt) => dlt.transactionLinkId) - @JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' }) - dltTransaction?: DltTransaction | null - - @OneToOne(() => User, (user) => user.transactionLink) - @JoinColumn({ name: 'userId' }) - user: User - - @OneToMany(() => Transaction, (transaction) => transaction.transactionLink) - @JoinColumn({ referencedColumnName: 'transaction_link_id' }) - transactions: Transaction[] -} diff --git a/database/entity/0089-merge_dlt_tables/User.ts b/database/entity/0089-merge_dlt_tables/User.ts deleted file mode 100644 index 64a6261ab..000000000 --- a/database/entity/0089-merge_dlt_tables/User.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { - BaseEntity, - Entity, - PrimaryGeneratedColumn, - Column, - DeleteDateColumn, - OneToMany, - JoinColumn, - OneToOne, - Geometry, - ManyToOne, -} from 'typeorm' -import { Contribution } from '../Contribution' -import { ContributionMessage } from '../ContributionMessage' -import { UserContact } from '../UserContact' -import { UserRole } from '../UserRole' -import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer' -import { Community } from '../Community' -import { DltTransaction } from '../DltTransaction' -import { TransactionLink } from './TransactionLink' - -@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) -export class User extends BaseEntity { - @PrimaryGeneratedColumn('increment', { unsigned: true }) - id: number - - @Column({ type: 'bool', default: false }) - foreign: boolean - - @Column({ - name: 'gradido_id', - length: 36, - nullable: false, - collation: 'utf8mb4_unicode_ci', - }) - gradidoID: string - - @Column({ - name: 'community_uuid', - type: 'char', - length: 36, - nullable: true, - collation: 'utf8mb4_unicode_ci', - }) - communityUuid: string - - @ManyToOne(() => Community, (community) => community.users) - @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) - community: Community | null - - @Column({ - name: 'alias', - length: 20, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - alias: string - - @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) - @JoinColumn({ name: 'email_id' }) - emailContact: UserContact - - @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) - emailId: number | null - - @Column({ - name: 'first_name', - length: 255, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - firstName: string - - @Column({ - name: 'last_name', - length: 255, - nullable: true, - default: null, - collation: 'utf8mb4_unicode_ci', - }) - lastName: string - - @Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) - gmsPublishName: number - - @Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 }) - humhubPublishName: number - - @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) - createdAt: Date - - @DeleteDateColumn({ name: 'deleted_at', nullable: true }) - deletedAt: Date | null - - @Column({ type: 'bigint', default: 0, unsigned: true }) - password: BigInt - - @Column({ - name: 'password_encryption_type', - type: 'int', - unsigned: true, - nullable: false, - default: 0, - }) - passwordEncryptionType: number - - @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) - language: string - - @Column({ type: 'bool', default: false }) - hideAmountGDD: boolean - - @Column({ type: 'bool', default: false }) - hideAmountGDT: boolean - - @OneToMany(() => UserRole, (userRole) => userRole.user) - @JoinColumn({ name: 'user_id' }) - userRoles: UserRole[] - - @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) - referrerId?: number | null - - @Column({ - name: 'contribution_link_id', - type: 'int', - unsigned: true, - nullable: true, - default: null, - }) - contributionLinkId?: number | null - - @Column({ name: 'publisher_id', default: 0 }) - publisherId: number - - @Column({ name: 'gms_allowed', type: 'bool', default: true }) - gmsAllowed: boolean - - @Column({ - name: 'location', - type: 'geometry', - default: null, - nullable: true, - transformer: GeometryTransformer, - }) - location: Geometry | null - - @Column({ - name: 'gms_publish_location', - type: 'int', - unsigned: true, - nullable: false, - default: 2, - }) - gmsPublishLocation: number - - @Column({ name: 'gms_registered', type: 'bool', default: false }) - gmsRegistered: boolean - - @Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true }) - gmsRegisteredAt: Date | null - - @Column({ name: 'humhub_allowed', type: 'bool', default: false }) - humhubAllowed: boolean - - @OneToMany(() => Contribution, (contribution) => contribution.user) - @JoinColumn({ name: 'user_id' }) - contributions?: Contribution[] - - @OneToMany(() => ContributionMessage, (message) => message.user) - @JoinColumn({ name: 'user_id' }) - messages?: ContributionMessage[] - - @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) - @JoinColumn({ name: 'user_id' }) - userContacts?: UserContact[] - - @OneToOne(() => DltTransaction, (dlt) => dlt.userId) - @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) - dltTransaction?: DltTransaction | null - - @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.userId) - @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) - transactionLink?: TransactionLink | null -} diff --git a/database/entity/DltTransaction.ts b/database/entity/DltTransaction.ts deleted file mode 100644 index bc3244dc0..000000000 --- a/database/entity/DltTransaction.ts +++ /dev/null @@ -1 +0,0 @@ -export { DltTransaction } from './0089-merge_dlt_tables/DltTransaction' diff --git a/database/entity/Transaction.ts b/database/entity/Transaction.ts deleted file mode 100644 index 2f4b2ccfc..000000000 --- a/database/entity/Transaction.ts +++ /dev/null @@ -1 +0,0 @@ -export { Transaction } from './0089-merge_dlt_tables/Transaction' diff --git a/database/entity/TransactionLink.ts b/database/entity/TransactionLink.ts deleted file mode 100644 index fa8af166d..000000000 --- a/database/entity/TransactionLink.ts +++ /dev/null @@ -1 +0,0 @@ -export { TransactionLink } from './0089-merge_dlt_tables/TransactionLink' diff --git a/database/entity/User.ts b/database/entity/User.ts deleted file mode 100644 index 92b529cb1..000000000 --- a/database/entity/User.ts +++ /dev/null @@ -1 +0,0 @@ -export { User } from './0089-merge_dlt_tables/User' diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index c06eedf8b..9c48800d8 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -75,6 +75,8 @@ export class HieroClient { this.logger.info( `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, ) + const record = await sendResponse.getRecordWithSigner(this.wallet) + this.logger.info(`message sent, cost: ${record.transactionFee.toString()}`) return { receipt: sendReceipt, response: sendResponse } } @@ -120,6 +122,8 @@ export class HieroClient { const createReceipt = await createResponse.getReceiptWithSigner(this.wallet) this.logger.debug(createReceipt.toString()) this.logger.addContext('topicId', createReceipt.topicId?.toString()) + const record = await createResponse.getRecordWithSigner(this.wallet) + this.logger.info(`topic created, cost: ${record.transactionFee.toString()}`) return parse(hieroIdSchema, createReceipt.topicId?.toString()) } @@ -133,5 +137,7 @@ export class HieroClient { const updateResponse = await transaction.executeWithSigner(this.wallet) const updateReceipt = await updateResponse.getReceiptWithSigner(this.wallet) this.logger.debug(updateReceipt.toString()) + const record = await updateResponse.getRecordWithSigner(this.wallet) + this.logger.info(`topic updated, cost: ${record.transactionFee.toString()}`) } } diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index cafd1a006..e2eb30a8a 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -87,7 +87,8 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): } else { // if topic exist, check if we need to update it let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) - if ( + console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`) + /*if ( topicInfo.expirationTime.getTime() - new Date().getTime() < MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE ) { @@ -96,7 +97,7 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): logger.info( `updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`, ) - } + }*/ } if (!homeCommunity.hieroTopicId) { throw new Error('still no topic id, after creating topic and update community in backend.') diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index c363ad263..996be0d10 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -88,19 +88,19 @@ export async function SendToHieroContext( if (builder.isCrossCommunityTransaction()) { const outboundTransaction = builder.buildOutbound() validate(outboundTransaction) - const outboundIotaMessageId = await sendViaHiero( + const outboundHieroTransactionId = await sendViaHiero( outboundTransaction, role.getSenderCommunityTopicId(), ) - builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundIotaMessageId))) + builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundHieroTransactionId))) const inboundTransaction = builder.buildInbound() validate(inboundTransaction) await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId()) - return parse(hieroTransactionIdSchema, outboundIotaMessageId) + return parse(hieroTransactionIdSchema, outboundHieroTransactionId) } else { const transaction = builder.build() validate(transaction) - const iotaMessageId = await sendViaHiero(transaction, role.getSenderCommunityTopicId()) - return parse(hieroTransactionIdSchema, iotaMessageId) + const hieroTransactionId = await sendViaHiero(transaction, role.getSenderCommunityTopicId()) + return parse(hieroTransactionIdSchema, hieroTransactionId) } } diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index c3a00d4e3..3aa13dcac 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,4 +1,5 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' +import { Type } from '@sinclair/typebox' import { Elysia, status } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' @@ -46,11 +47,30 @@ export const appRoutes = new Elysia() ) .post( '/sendTransaction', - async ({ body }) => await SendToHieroContext(parse(transactionSchema, body)), + async ({ body }) => { + console.log("sendTransaction was called") + return "0.0.123" + console.log(body) + console.log(parse(transactionSchema, body)) + const transaction = parse(transactionSchema, body) + return await SendToHieroContext(transaction) + }, // validation schemas { - body: TypeBoxFromValibot(transactionSchema), - response: TypeBoxFromValibot(hieroTransactionIdSchema), + // body: TypeBoxFromValibot(transactionSchema), + body: Type.Object({ + user: Type.Object({ + communityUser: Type.Object({ + uuid: Type.String({ format: 'uuid' }), + accountNr: Type.Optional(Type.String()), // optional/undefined + }), + communityUuid: Type.String({ format: 'uuid' }), + }), + createdAt: Type.String({ format: 'date-time' }), + accountType: Type.Literal('COMMUNITY_HUMAN'), + type: Type.Literal('REGISTER_ADDRESS'), + }) + // response: TypeBoxFromValibot(hieroTransactionIdSchema), }, ) @@ -76,3 +96,4 @@ async function isAccountExist(identifierAccount: IdentifierAccount): Promise Date: Sat, 20 Sep 2025 15:21:55 +0200 Subject: [PATCH 033/226] simplify backend code for dlt connector calling --- .../apis/dltConnector/DltConnectorClient.ts | 7 +- .../dltConnector/enum/TransactionErrorType.ts | 14 - backend/src/apis/dltConnector/index.ts | 107 +++ .../AbstractTransactionToDlt.role.ts | 63 -- .../TransactionLinkDeleteToDlt.role.ts | 94 --- .../TransactionLinkToDlt.role.ts | 68 -- .../transactionToDlt/TransactionToDlt.role.ts | 105 --- .../transactionToDlt/UserToDlt.role.ts | 61 -- .../transactionToDlt.context.ts | 67 -- .../dltConnector/model/TransactionDraft.ts | 59 +- .../sendTransactionsToDltConnector.test.ts | 728 ------------------ .../sendTransactionsToDltConnector.ts | 69 -- .../graphql/resolver/ContributionResolver.ts | 36 +- .../graphql/resolver/TransactionResolver.ts | 21 +- backend/src/graphql/resolver/UserResolver.ts | 26 +- backend/src/index.ts | 2 +- dlt-connector/bun.lock | 2 +- dlt-connector/package.json | 2 +- .../client/backend/community.schema.test.ts | 2 + dlt-connector/src/client/hiero/HieroClient.ts | 17 +- .../src/data/KeyPairIdentifier.logic.ts | 8 +- dlt-connector/src/index.ts | 1 - .../KeyPairCalculation.context.test.ts | 99 +++ .../sendToHiero/CreationTransaction.role.ts | 7 +- .../RegisterAddressTransaction.role.test.ts | 35 + .../RegisterAddressTransaction.role.ts | 18 +- .../sendToHiero/SendToHiero.context.ts | 37 +- dlt-connector/src/schemas/account.schema.ts | 16 +- .../src/schemas/transaction.schema.test.ts | 69 +- .../src/schemas/transaction.schema.ts | 15 +- .../src/schemas/typeConverter.schema.test.ts | 41 +- .../src/schemas/typeConverter.schema.ts | 2 +- dlt-connector/src/schemas/typeGuard.schema.ts | 34 +- dlt-connector/src/server/index.test.ts | 75 ++ dlt-connector/src/server/index.ts | 37 +- 35 files changed, 639 insertions(+), 1405 deletions(-) delete mode 100644 backend/src/apis/dltConnector/enum/TransactionErrorType.ts create mode 100644 backend/src/apis/dltConnector/index.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts delete mode 100644 backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts delete mode 100644 backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts delete mode 100644 backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts create mode 100644 dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts create mode 100644 dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts create mode 100644 dlt-connector/src/server/index.test.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 16c74ab0c..a5e162ba0 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -58,8 +58,11 @@ export class DltConnectorClient { * transmit transaction via dlt-connector to hiero * and update dltTransactionId of transaction in db with hiero transaction id */ - public async sendTransaction(input: TransactionDraft): Promise> { + public async sendTransaction(input: TransactionDraft): Promise> { logger.debug('transmit transaction or user to dlt connector', input) - return await this.client.create('/sendTransaction', input) + return await this.client.create<{ transactionId: string }>( + '/sendTransaction', + input + ) } } diff --git a/backend/src/apis/dltConnector/enum/TransactionErrorType.ts b/backend/src/apis/dltConnector/enum/TransactionErrorType.ts deleted file mode 100644 index 5a2c5485e..000000000 --- a/backend/src/apis/dltConnector/enum/TransactionErrorType.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Error Types for dlt-connector graphql responses - */ -export enum TransactionErrorType { - NOT_IMPLEMENTED_YET = 'Not Implemented yet', - MISSING_PARAMETER = 'Missing parameter', - ALREADY_EXIST = 'Already exist', - DB_ERROR = 'DB Error', - PROTO_DECODE_ERROR = 'Proto Decode Error', - PROTO_ENCODE_ERROR = 'Proto Encode Error', - INVALID_SIGNATURE = 'Invalid Signature', - LOGIC_ERROR = 'Logic Error', - NOT_FOUND = 'Not found', -} diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts new file mode 100644 index 000000000..7780006e9 --- /dev/null +++ b/backend/src/apis/dltConnector/index.ts @@ -0,0 +1,107 @@ +import { IRestResponse } from 'typed-rest-client' +import { DltTransactionType } from './enum/DltTransactionType' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' +import { DltConnectorClient } from './DltConnectorClient' +import { + Community as DbCommunity, + Contribution as DbContribution, + DltTransaction as DbDltTransaction, + User as DbUser, + getHomeCommunity, +} from 'database' +import { TransactionDraft } from './model/TransactionDraft' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector`) +// will be undefined if dlt connect is disabled +const dltConnectorClient = DltConnectorClient.getInstance() + +async function checkDltConnectorResult(dltTransaction: DbDltTransaction, clientResponse: Promise>) + : Promise { + // check result from dlt connector + try { + const response = await clientResponse + if (response.statusCode === 200 && response.result) { + dltTransaction.messageId = response.result.transactionId + } else { + dltTransaction.error = `empty result with status code ${response.statusCode}` + logger.error('error from dlt-connector', response) + } + } catch (e) { + logger.debug(e) + if (e instanceof Error) { + dltTransaction.error = e.message + } else if (typeof e === 'string') { + dltTransaction.error = e + } else { + throw e + } + } + return dltTransaction +} + +/** + * send register address transaction via dlt-connector to hiero + * and update dltTransactionId of transaction in db with hiero transaction id + */ +export async function registerAddressTransaction(user: DbUser, community: DbCommunity): Promise { + if (!user.id) { + logger.error(`missing id for user: ${user.gradidoID}, please call registerAddressTransaction after user.save()`) + return null + } + // return null if some data where missing and log error + const draft = TransactionDraft.createRegisterAddress(user, community) + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = DltTransactionType.REGISTER_ADDRESS + if (user.id) { + dltTransaction.userId = user.id + } + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + return await dltTransaction.save() + } + return null +} + +export async function contributionTransaction( + contribution: DbContribution, + signingUser: DbUser, + createdAt: Date, +): Promise { + const homeCommunity = await getHomeCommunity() + if (!homeCommunity) { + logger.error('home community not found') + return null + } + const draft = TransactionDraft.createContribution(contribution, createdAt, signingUser, homeCommunity) + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = DltTransactionType.CREATION + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + return await dltTransaction.save() + } + return null +} + +export async function transferTransaction( + senderUser: DbUser, + recipientUser: DbUser, + amount: string, + memo: string, + createdAt: Date +): Promise { + + const draft = TransactionDraft.createTransfer(senderUser, recipientUser, amount, memo, createdAt) + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = DltTransactionType.TRANSFER + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + return await dltTransaction.save() + } + return null +} + + diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts deleted file mode 100644 index 22f7104b2..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/AbstractTransactionToDlt.role.ts +++ /dev/null @@ -1,63 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from 'typeorm' -import { DltTransaction } from 'database' - -import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { Logger } from 'log4js' - -export abstract class AbstractTransactionToDltRole { - protected self: T | null - - // public interface - public abstract initWithLast(): Promise - public abstract getTimestamp(): number - public abstract convertToGraphqlInput(): TransactionDraft - - - public constructor(protected logger: Logger) {} - - public getEntity(): T | null { - return this.self - } - - public async saveTransactionResult(messageId: string, error: string | null): Promise { - const dltTransaction = DltTransaction.create() - dltTransaction.messageId = messageId - dltTransaction.error = error - this.setJoinIdAndType(dltTransaction) - await DltTransaction.save(dltTransaction) - if (dltTransaction.error) { - this.logger.error( - `Store dltTransaction with error: id=${dltTransaction.id}, error=${dltTransaction.error}`, - ) - } else { - this.logger.info( - `Store dltTransaction: messageId=${dltTransaction.messageId}, id=${dltTransaction.id}`, - ) - } - } - - // intern - protected abstract setJoinIdAndType(dltTransaction: DltTransaction): void - - // helper - protected createQueryForPendingItems( - qb: SelectQueryBuilder, - joinCondition: string, - orderBy: OrderByCondition, - ): SelectQueryBuilder { - return qb - .leftJoin(DltTransaction, 'dltTransaction', joinCondition) - .where('dltTransaction.user_id IS NULL') - .andWhere('dltTransaction.transaction_id IS NULL') - .andWhere('dltTransaction.transaction_link_Id IS NULL') - .orderBy(orderBy) - } - - protected createDltTransactionEntry(messageId: string, error: string | null): DltTransaction { - const dltTransaction = DltTransaction.create() - dltTransaction.messageId = messageId - dltTransaction.error = error - return dltTransaction - } -} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts deleted file mode 100644 index d4964a9f8..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkDeleteToDlt.role.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { DltTransaction, TransactionLink } from 'database' - -import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' -import { TransactionType } from '@dltConnector/enum/TransactionType' -import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' -import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier' - -import { LogError } from '@/server/LogError' - -import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' -import { CommunityAccountIdentifier } from '@dltConnector/model/CommunityAccountIdentifier' - -/** - * redeem deferred transfer transaction by creator, so "deleting" it - */ -export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole { - async initWithLast(): Promise { - const queryBuilder = this.createQueryForPendingItems( - TransactionLink - .createQueryBuilder() - .leftJoinAndSelect('TransactionLink.user', 'user') - .leftJoinAndSelect('user.community', 'community'), - 'TransactionLink.id = dltTransaction.transactionLinkId and dltTransaction.type_id <> 4', - // eslint-disable-next-line camelcase - { TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }, - ) - .andWhere('TransactionLink.deletedAt IS NOT NULL') - .withDeleted() - /* - const queryBuilder2 = TransactionLink.createQueryBuilder() - .leftJoinAndSelect('TransactionLink.user', 'user') - .where('TransactionLink.deletedAt IS NOT NULL') - .andWhere(() => { - const subQuery = DltTransaction.createQueryBuilder() - .select('1') - .where('DltTransaction.transaction_link_id = TransactionLink.id') - .andWhere('DltTransaction.type_id = :typeId', { - typeId: DltTransactionType.DELETE_DEFERRED_TRANSFER, - }) - .getQuery() - return `NOT EXIST (${subQuery})` - }) - .withDeleted() - // eslint-disable-next-line camelcase - .orderBy({ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' }) - */ - // console.log('query: ', queryBuilder.getSql()) - this.self = await queryBuilder.getOne() - return this - } - - public getTimestamp(): number { - if (!this.self) { - return Infinity - } - if (!this.self.deletedAt) { - throw new LogError('not deleted transaction link selected') - } - return this.self.deletedAt.getTime() - } - - public convertToGraphqlInput(): TransactionDraft { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction link') - } - if (!this.self.deletedAt) { - throw new LogError('not deleted transaction link selected') - } - const draft = new TransactionDraft() - draft.amount = this.self.amount.abs().toString() - const user = this.self.user - if (!user.community) { - throw new LogError(`missing community for user ${user.id}`) - } - const topicId = user.community.hieroTopicId - if (!topicId) { - throw new LogError(`missing topicId for community ${user.community.id}`) - } - draft.user = new AccountIdentifier(topicId, new IdentifierSeed(this.self.code)) - draft.linkedUser = new AccountIdentifier(topicId, new CommunityAccountIdentifier(user.gradidoID)) - draft.createdAt = this.self.deletedAt.toISOString() - draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER - return draft - } - - protected setJoinIdAndType(dltTransaction: DltTransaction): void { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction link') - } - dltTransaction.transactionLinkId = this.self.id - dltTransaction.typeId = DltTransactionType.DELETE_DEFERRED_TRANSFER - } -} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts deleted file mode 100644 index 05f9d319e..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionLinkToDlt.role.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { DltTransaction, TransactionLink } from 'database' - -import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' -import { TransactionType } from '@dltConnector/enum/TransactionType' -import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' -import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier' - -import { LogError } from '@/server/LogError' - -import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' -import { CommunityAccountIdentifier } from '../../model/CommunityAccountIdentifier' - -/** - * send transactionLink as Deferred Transfers - */ -export class TransactionLinkToDltRole extends AbstractTransactionToDltRole { - async initWithLast(): Promise { - this.self = await this.createQueryForPendingItems( - TransactionLink - .createQueryBuilder() - .leftJoinAndSelect('TransactionLink.user', 'user') - .leftJoinAndSelect('user.community', 'community'), - 'TransactionLink.id = dltTransaction.transactionLinkId', - // eslint-disable-next-line camelcase - { TransactionLink_createdAt: 'ASC', User_id: 'ASC' }, - ).getOne() - return this - } - - public getTimestamp(): number { - if (!this.self) { - return Infinity - } - return this.self.createdAt.getTime() - } - - public convertToGraphqlInput(): TransactionDraft { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction link') - } - const draft = new TransactionDraft() - draft.amount = this.self.amount.abs().toString() - const user = this.self.user - if (!user.community) { - throw new LogError(`missing community for user ${user.id}`) - } - const topicId = user.community.hieroTopicId - if (!topicId) { - throw new LogError(`missing topicId for community ${user.community.id}`) - } - draft.user = new AccountIdentifier(topicId, new CommunityAccountIdentifier(user.gradidoID, 1)) - draft.linkedUser = new AccountIdentifier(topicId, new IdentifierSeed(this.self.code)) - draft.createdAt = this.self.createdAt.toISOString() - draft.timeoutDuration = (this.self.validUntil.getTime() - this.self.createdAt.getTime()) / 1000 - draft.memo = this.self.memo - draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER - return draft - } - - protected setJoinIdAndType(dltTransaction: DltTransaction): void { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction link') - } - dltTransaction.transactionLinkId = this.self.id - dltTransaction.typeId = DltTransactionType.DEFERRED_TRANSFER - } -} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts deleted file mode 100644 index 63f25d22d..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/TransactionToDlt.role.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { DltTransaction, Transaction } from 'database' - -import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' -import { TransactionType } from '@dltConnector/enum/TransactionType' -import { CommunityUser } from '@dltConnector/model/CommunityUser' -import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed' -import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { UserIdentifier } from '@/apis/dltConnector/model/AccountIdentifier' - -import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' -import { LogError } from '@/server/LogError' - -import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' - -/** - * send transfer and creations transactions to dlt connector as GradidoTransfer and GradidoCreation - */ -export class TransactionToDltRole extends AbstractTransactionToDltRole { - private type: DltTransactionType - async initWithLast(): Promise { - this.self = await this.createQueryForPendingItems( - Transaction.createQueryBuilder().leftJoinAndSelect( - 'Transaction.transactionLink', - 'transactionLink', - ), - 'Transaction.id = dltTransaction.transactionId', - // eslint-disable-next-line camelcase - { balance_date: 'ASC', Transaction_id: 'ASC' }, - ) - // we don't need the receive transactions, there contain basically the same data as the send transactions - .andWhere('Transaction.type_id <> :typeId', { typeId: TransactionTypeId.RECEIVE }) - .getOne() - return this - } - - public getTimestamp(): number { - if (!this.self) { - return Infinity - } - return this.self.balanceDate.getTime() - } - - public convertToGraphqlInput(): TransactionDraft { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction') - } - const draft = new TransactionDraft() - draft.amount = this.self.amount.abs().toString() - - switch (this.self.typeId as TransactionTypeId) { - case TransactionTypeId.CREATION: - draft.type = TransactionType.GRADIDO_CREATION - this.type = DltTransactionType.CREATION - break - case TransactionTypeId.SEND: - case TransactionTypeId.RECEIVE: - draft.type = TransactionType.GRADIDO_TRANSFER - this.type = DltTransactionType.TRANSFER - break - default: - this.type = DltTransactionType.UNKNOWN - throw new LogError('wrong role for type', this.self.typeId as TransactionTypeId) - } - if ( - !this.self.linkedUserGradidoID || - !this.self.linkedUserCommunityUuid || - !this.self.userCommunityUuid - ) { - throw new LogError( - `missing necessary field in transaction: ${this.self.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`, - ) - } - // it is a redeem of a transaction link? - const transactionLink = this.self.transactionLink - if (transactionLink) { - draft.user = new UserIdentifier( - this.self.userCommunityUuid, - new IdentifierSeed(transactionLink.code), - ) - draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER - this.type = DltTransactionType.REDEEM_DEFERRED_TRANSFER - } else { - draft.user = new UserIdentifier( - this.self.userCommunityUuid, - new CommunityUser(this.self.userGradidoID, 1), - ) - } - draft.linkedUser = new UserIdentifier( - this.self.linkedUserCommunityUuid, - new CommunityUser(this.self.linkedUserGradidoID, 1), - ) - draft.memo = this.self.memo - draft.createdAt = this.self.balanceDate.toISOString() - draft.targetDate = this.self.creationDate?.toISOString() - return draft - } - - protected setJoinIdAndType(dltTransaction: DltTransaction): void { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction') - } - dltTransaction.transactionId = this.self.id - dltTransaction.typeId = this.type - } -} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts deleted file mode 100644 index d302a36b3..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/UserToDlt.role.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { DltTransaction, User } from 'database' - -import { AccountType } from '@dltConnector/enum/AccountType' -import { DltTransactionType } from '@dltConnector/enum/DltTransactionType' -import { TransactionType } from '@dltConnector/enum/TransactionType' -import { TransactionDraft } from '@dltConnector/model/TransactionDraft' -import { AccountIdentifier } from '@/apis/dltConnector/model/AccountIdentifier' - -import { LogError } from '@/server/LogError' - -import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' -import { CommunityAccountIdentifier } from '../../model/CommunityAccountIdentifier' - -/** - * send new user to dlt connector, will be made to RegisterAddress Transaction - */ -export class UserToDltRole extends AbstractTransactionToDltRole { - async initWithLast(): Promise { - this.self = await this.createQueryForPendingItems( - User.createQueryBuilder().leftJoinAndSelect('User.community', 'community'), - 'User.id = dltTransaction.userId', - // eslint-disable-next-line camelcase - { User_created_at: 'ASC', User_id: 'ASC' }, - ).getOne() - return this - } - - public getTimestamp(): number { - if (!this.self) { - return Infinity - } - return this.self.createdAt.getTime() - } - - public convertToGraphqlInput(): TransactionDraft { - if (!this.self) { - throw new LogError('try to create dlt entry for empty transaction') - } - if (!this.self.community) { - throw new LogError(`missing community for user ${this.self.id}`) - } - const topicId = this.self.community.hieroTopicId - if (!topicId) { - throw new LogError(`missing topicId for community ${this.self.community.id}`) - } - const draft = new TransactionDraft() - draft.user = new AccountIdentifier(topicId, new CommunityAccountIdentifier(this.self.gradidoID)) - draft.createdAt = this.self.createdAt.toISOString() - draft.accountType = AccountType.COMMUNITY_HUMAN - draft.type = TransactionType.REGISTER_ADDRESS - return draft - } - - protected setJoinIdAndType(dltTransaction: DltTransaction): void { - if (!this.self) { - throw new LogError('try to create dlt entry for empty user') - } - dltTransaction.userId = this.self.id - dltTransaction.typeId = DltTransactionType.REGISTER_ADDRESS - } -} diff --git a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts b/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts deleted file mode 100644 index cb1d8cca2..000000000 --- a/backend/src/apis/dltConnector/interaction/transactionToDlt/transactionToDlt.context.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Transaction, TransactionLink, User } from 'database' - -import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient' - -import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role' -import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role' -import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role' -import { TransactionToDltRole } from './TransactionToDlt.role' -import { UserToDltRole } from './UserToDlt.role' -import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' - -/** - * @DCI-Context - * Context for sending transactions to dlt connector, always the oldest not sended transaction first - */ -export async function transactionToDlt(dltConnector: DltConnectorClient): Promise { - async function findNextPendingTransaction(logger: Logger): Promise< - AbstractTransactionToDltRole - > { - // collect each oldest not sended entity from db and choose oldest - const results = await Promise.all([ - new TransactionToDltRole(logger).initWithLast(), - new UserToDltRole(logger).initWithLast(), - new TransactionLinkToDltRole(logger).initWithLast(), - new TransactionLinkDeleteToDltRole(logger).initWithLast(), - ]) - - // sort array to get oldest at first place - results.sort((a, b) => { - return a.getTimestamp() - b.getTimestamp() - }) - return results[0] - } - - const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.interaction.transactionToDlt`) - while (true) { - const pendingTransactionRole = await findNextPendingTransaction(logger) - const pendingTransaction = pendingTransactionRole.getEntity() - if (!pendingTransaction) { - break - } - let messageId = '' - let error: string | null = null - try { - const result = await dltConnector.sendTransaction( - pendingTransactionRole.convertToGraphqlInput() - ) - if (result.statusCode === 200 && result.result) { - messageId = result.result - } else { - error = `empty result with status code ${result.statusCode}` - logger.error('error from dlt-connector', result) - } - } catch (e) { - logger.debug(e) - if (e instanceof Error) { - error = e.message - } else if (typeof e === 'string') { - error = e - } else { - throw e - } - } - await pendingTransactionRole.saveTransactionResult(messageId, error) - } -} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 8dba79bdc..1342a3f8f 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -3,6 +3,12 @@ import { AccountType } from '@dltConnector/enum/AccountType' import { TransactionType } from '@dltConnector/enum/TransactionType' import { AccountIdentifier } from './AccountIdentifier' +import { Community as DbCommunity, Contribution as DbContribution, User as DbUser } from 'database' +import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector.model.TransactionDraft`) export class TransactionDraft { user: AccountIdentifier @@ -19,4 +25,55 @@ export class TransactionDraft { timeoutDuration?: number // only for register address accountType?: AccountType -} + + static createRegisterAddress(user: DbUser, community: DbCommunity): TransactionDraft | null { + if (community.hieroTopicId) { + const draft = new TransactionDraft() + draft.user = new AccountIdentifier(community.hieroTopicId, new CommunityAccountIdentifier(user.gradidoID)) + draft.type = TransactionType.REGISTER_ADDRESS + draft.createdAt = user.createdAt.toISOString() + draft.accountType = AccountType.COMMUNITY_HUMAN + return draft + } else { + logger.warn(`missing topicId for community ${community.id}`) + } + return null + } + + static createContribution(contribution: DbContribution, createdAt: Date, signingUser: DbUser, community: DbCommunity): TransactionDraft | null { + if (community.hieroTopicId) { + const draft = new TransactionDraft() + draft.user = new AccountIdentifier(community.hieroTopicId, new CommunityAccountIdentifier(contribution.user.gradidoID)) + draft.linkedUser = new AccountIdentifier(community.hieroTopicId, new CommunityAccountIdentifier(signingUser.gradidoID)) + draft.type = TransactionType.GRADIDO_CREATION + draft.createdAt = createdAt.toISOString() + draft.amount = contribution.amount.toString() + draft.memo = contribution.memo + draft.targetDate = contribution.contributionDate.toISOString() + return draft + } else { + logger.warn(`missing topicId for community ${community.id}`) + } + return null + } + + static createTransfer(sendingUser: DbUser, receivingUser: DbUser, amount: string, memo: string, createdAt: Date): TransactionDraft | null { + if (!sendingUser.community || !receivingUser.community) { + logger.warn(`missing community for user ${sendingUser.id} and/or ${receivingUser.id}`) + return null + } + if (sendingUser.community.hieroTopicId && receivingUser.community.hieroTopicId) { + const draft = new TransactionDraft() + draft.user = new AccountIdentifier(sendingUser.community.hieroTopicId, new CommunityAccountIdentifier(sendingUser.gradidoID)) + draft.linkedUser = new AccountIdentifier(receivingUser.community.hieroTopicId, new CommunityAccountIdentifier(receivingUser.gradidoID)) + draft.type = TransactionType.GRADIDO_TRANSFER + draft.createdAt = createdAt.toISOString() + draft.amount = amount + draft.memo = memo + return draft + } else { + logger.warn(`missing topicId for community ${community.id}`) + } + return null + } +} \ No newline at end of file diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts deleted file mode 100644 index 50af15e9a..000000000 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.test.ts +++ /dev/null @@ -1,728 +0,0 @@ -import { Community, DltTransaction, Transaction } from 'database' -import { Decimal } from 'decimal.js-light' -import { Response } from 'graphql-request/dist/types' -import { DataSource } from 'typeorm' -import { v4 as uuidv4 } from 'uuid' - -import { cleanDB, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' - -import { CONFIG } from '@/config' -import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' -import { creations } from '@/seeds/creation' -import { creationFactory } from '@/seeds/factory/creation' -import { userFactory } from 'database/src/seeds/factory/user' -import { bibiBloxberg } from 'database/src/seeds/users/bibi-bloxberg' -import { bobBaumeister } from 'database/src/seeds/users/bob-baumeister' -import { peterLustig } from 'database/src/seeds/users/peter-lustig' -import { raeuberHotzenplotz } from 'database/src/seeds/users/raeuber-hotzenplotz' -import { getLogger } from 'config-schema/test/testSetup' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' - -import { sendTransactionsToDltConnector } from './sendTransactionsToDltConnector' - -jest.mock('@/password/EncryptorUtils') - -const logger = getLogger( - `${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.sendTransactionsToDltConnector`, -) - -async function createHomeCommunity(): Promise { - const homeCommunity = Community.create() - homeCommunity.foreign = false - homeCommunity.communityUuid = uuidv4() - homeCommunity.url = 'localhost' - homeCommunity.publicKey = Buffer.from('0x6e6a6c6d6feffe', 'hex') - await Community.save(homeCommunity) - return homeCommunity -} - -async function createTxCREATION1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(100) - tx.balanceDate = new Date('01.01.2023 00:00:00') - tx.memo = 'txCREATION1' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION1.userGradidoID' - tx.userId = 1 - tx.userName = 'txCREATION 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('01.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('01.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxCREATION2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(200) - tx.balanceDate = new Date('02.01.2023 00:00:00') - tx.memo = 'txCREATION2' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION2.userGradidoID' - tx.userId = 2 - tx.userName = 'txCREATION 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('02.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('02.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxCREATION3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(300) - tx.balanceDate = new Date('03.01.2023 00:00:00') - tx.memo = 'txCREATION3' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION3.userGradidoID' - tx.userId = 3 - tx.userName = 'txCREATION 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('03.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('03.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxSend1ToReceive2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(100) - tx.balance = new Decimal(1000) - tx.balanceDate = new Date('11.01.2023 00:00:00') - tx.memo = 'txSEND1 to txRECEIVE2' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND1.userGradidoID' - tx.userId = 1 - tx.userName = 'txSEND 1' - tx.linkedUserGradidoID = 'txRECEIVE2.linkedUserGradidoID' - tx.linkedUserId = 2 - tx.linkedUserName = 'txRECEIVE 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('11.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('11.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive2FromSend1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(100) - tx.balance = new Decimal(1300) - tx.balanceDate = new Date('11.01.2023 00:00:00') - tx.memo = 'txSEND1 to txRECEIVE2' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE2.linkedUserGradidoID' - tx.userId = 2 - tx.userName = 'txRECEIVE 2' - tx.linkedUserGradidoID = 'txSEND1.userGradidoID' - tx.linkedUserId = 1 - tx.linkedUserName = 'txSEND 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('11.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('11.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -/* -async function createTxSend2ToReceive3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(200) - tx.balance = new Decimal(1100) - tx.balanceDate = new Date('23.01.2023 00:00:00') - tx.memo = 'txSEND2 to txRECEIVE3' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND2.userGradidoID' - tx.userId = 2 - tx.userName = 'txSEND 2' - tx.linkedUserGradidoID = 'txRECEIVE3.linkedUserGradidoID' - tx.linkedUserId = 3 - tx.linkedUserName = 'txRECEIVE 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('23.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('23.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive3FromSend2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(200) - tx.balance = new Decimal(1500) - tx.balanceDate = new Date('23.01.2023 00:00:00') - tx.memo = 'txSEND2 to txRECEIVE3' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE3.linkedUserGradidoID' - tx.userId = 3 - tx.userName = 'txRECEIVE 3' - tx.linkedUserGradidoID = 'txSEND2.userGradidoID' - tx.linkedUserId = 2 - tx.linkedUserName = 'txSEND 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('23.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('23.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxSend3ToReceive1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(300) - tx.balance = new Decimal(1200) - tx.balanceDate = new Date('31.01.2023 00:00:00') - tx.memo = 'txSEND3 to txRECEIVE1' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND3.userGradidoID' - tx.userId = 3 - tx.userName = 'txSEND 3' - tx.linkedUserGradidoID = 'txRECEIVE1.linkedUserGradidoID' - tx.linkedUserId = 1 - tx.linkedUserName = 'txRECEIVE 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('31.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('31.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive1FromSend3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(300) - tx.balance = new Decimal(1300) - tx.balanceDate = new Date('31.01.2023 00:00:00') - tx.memo = 'txSEND3 to txRECEIVE1' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE1.linkedUserGradidoID' - tx.userId = 1 - tx.userName = 'txRECEIVE 1' - tx.linkedUserGradidoID = 'txSEND3.userGradidoID' - tx.linkedUserId = 3 - tx.linkedUserName = 'txSEND 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('31.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('31.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} -*/ - -let con: DataSource -let testEnv: { - con: DataSource -} - -beforeAll(async () => { - testEnv = await testEnvironment(logger, localization) - con = testEnv.con - await cleanDB() -}) - -afterAll(async () => { - await cleanDB() - await con.destroy() -}) - -describe('create and send Transactions to DltConnector', () => { - let txCREATION1: Transaction - let txCREATION2: Transaction - let txCREATION3: Transaction - let txSEND1to2: Transaction - let txRECEIVE2From1: Transaction - // let txSEND2To3: Transaction - // let txRECEIVE3From2: Transaction - // let txSEND3To1: Transaction - // let txRECEIVE1From3: Transaction - - beforeEach(() => { - jest.clearAllMocks() - }) - - afterEach(async () => { - await cleanDB() - }) - - describe('with 3 creations but inactive dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - txCREATION1 = await createTxCREATION1(false) - txCREATION2 = await createTxCREATION2(false) - txCREATION3 = await createTxCREATION3(false) - await createHomeCommunity() - - CONFIG.DLT_CONNECTOR = false - await sendTransactionsToDltConnector() - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[0].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[1].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[2].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - - expect(logger.info).nthCalledWith(2, 'sending to DltConnector currently not configured...') - }) - }) - - describe('with 3 creations and active dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - await userFactory(testEnv, raeuberHotzenplotz) - await userFactory(testEnv, bobBaumeister) - let count = 0 - for (const creation of creations) { - await creationFactory(testEnv, creation) - count++ - // we need only 3 for testing - if (count >= 3) { - break - } - } - await createHomeCommunity() - - CONFIG.DLT_CONNECTOR = true - - await sendTransactionsToDltConnector() - - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[0].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[1].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[2].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - }) - }) - - describe('with 3 verified creations, 1 sendCoins and active dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - txCREATION1 = await createTxCREATION1(true) - txCREATION2 = await createTxCREATION2(true) - txCREATION3 = await createTxCREATION3(true) - await createHomeCommunity() - - txSEND1to2 = await createTxSend1ToReceive2(false) - txRECEIVE2From1 = await createTxReceive2FromSend1(false) - - /* - txSEND2To3 = await createTxSend2ToReceive3() - txRECEIVE3From2 = await createTxReceive3FromSend2() - txSEND3To1 = await createTxSend3ToReceive1() - txRECEIVE1From3 = await createTxReceive1FromSend3() - */ - - CONFIG.DLT_CONNECTOR = true - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - return { - data: { - sendTransaction: { succeed: true }, - }, - } as Response - }) - - await sendTransactionsToDltConnector() - - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - /* - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - */ - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION1.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c1', - verified: true, - createdAt: new Date('01.01.2023 00:00:10'), - verifiedAt: new Date('01.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION2.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c2', - verified: true, - createdAt: new Date('02.01.2023 00:00:10'), - verifiedAt: new Date('02.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION3.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c3', - verified: true, - createdAt: new Date('03.01.2023 00:00:10'), - verifiedAt: new Date('03.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txSEND1to2.id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txRECEIVE2From1.id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - }) - /* - describe('with one Community of api 1_0 and not matching pubKey', () => { - beforeEach(async () => { - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: 'somePubKey', - }, - }, - } as Response - }) - const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables1) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - - jest.clearAllMocks() - // await validateCommunities() - }) - - it('logs one community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs not matching publicKeys', () => { - expect(logger.warn).toBeCalledWith( - 'Federation: received not matching publicKey:', - 'somePubKey', - expect.stringMatching('11111111111111111111111111111111'), - ) - }) - }) - describe('with one Community of api 1_0 and matching pubKey', () => { - beforeEach(async () => { - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: '11111111111111111111111111111111', - }, - }, - } as Response - }) - const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables1) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - - it('logs one community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs community pubKey verified', () => { - expect(logger.info).toHaveBeenNthCalledWith( - 3, - 'Federation: verified community with', - 'http//localhost:5001/api/', - ) - }) - }) - describe('with two Communities of api 1_0 and 1_1', () => { - beforeEach(async () => { - jest.clearAllMocks() - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: '11111111111111111111111111111111', - }, - }, - } as Response - }) - const variables2 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_1', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables2) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - it('logs two communities found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 2 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs requestGetPublicKey for community api 1_1 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_1/', - ) - }) - }) - describe('with three Communities of api 1_0, 1_1 and 2_0', () => { - let dbCom: DbFederatedCommunity - beforeEach(async () => { - const variables3 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '2_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables3) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - dbCom = await DbFederatedCommunity.findOneOrFail({ - where: { publicKey: variables3.publicKey, apiVersion: variables3.apiVersion }, - }) - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - it('logs three community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 3 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs requestGetPublicKey for community api 1_1 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_1/', - ) - }) - it('logs unsupported api for community with api 2_0 ', () => { - expect(logger.warn).toBeCalledWith( - 'Federation: dbCom with unsupported apiVersion', - dbCom.endPoint, - '2_0', - ) - }) - }) - */ - }) -}) diff --git a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts b/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts deleted file mode 100644 index ef58ed606..000000000 --- a/backend/src/apis/dltConnector/sendTransactionsToDltConnector.ts +++ /dev/null @@ -1,69 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { CONFIG } from '@/config' -import { TypeORMError } from 'typeorm' -// eslint-disable-next-line import/named, n/no-extraneous-import -import { FetchError } from 'node-fetch' - -import { DltConnectorClient } from '@dltConnector/DltConnectorClient' - -import { LogError } from '@/server/LogError' -import { - InterruptiveSleepManager, - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, -} from '@/util/InterruptiveSleepManager' - -import { transactionToDlt } from './interaction/transactionToDlt/transactionToDlt.context' -import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.sendTransactionsToDltConnector`) - -let isLoopRunning = true - -export const stopSendTransactionsToDltConnector = (): void => { - isLoopRunning = false -} - -export async function sendTransactionsToDltConnector(): Promise { - const dltConnector = DltConnectorClient.getInstance() - - if (!dltConnector) { - logger.info('currently not configured...') - isLoopRunning = false - return - } - logger.info('task started') - - // define outside of loop for reuse and reducing gb collection - // const queries = getFindNextPendingTransactionQueries() - - // eslint-disable-next-line no-unmodified-loop-condition - while (isLoopRunning) { - try { - // return after no pending transactions are left - await transactionToDlt(dltConnector) - await InterruptiveSleepManager.getInstance().sleep( - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, - // TODO: put sleep time into config, because it influence performance, - // transactionToDlt call 4 db queries to look for new transactions - CONFIG.PRODUCTION ? 100000 : 1000, - ) - } catch (e) { - // couldn't connect to dlt-connector? We wait - if (e instanceof FetchError) { - logger.error(`error connecting dlt-connector, wait 5 seconds before retry: ${String(e)}`) - await InterruptiveSleepManager.getInstance().sleep( - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, - 5000, - ) - } else { - if (e instanceof TypeORMError) { - // seems to be a error in code, so let better stop here - throw new LogError(e.message, e.stack) - } else { - logger.error(`Error while sending to DLT-connector or writing messageId`, e) - } - } - } - } -} diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index f5ed2f1d2..34ea8b1da 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,6 +2,7 @@ import { Contribution as DbContribution, Transaction as DbTransaction, User as DbUser, + DltTransaction as DbDltTransaction, UserContact, } from 'database' import { Decimal } from 'decimal.js-light' @@ -60,6 +61,7 @@ import { extractGraphQLFields } from './util/extractGraphQLFields' import { findContributions } from './util/findContributions' import { getLastTransaction } from './util/getLastTransaction' import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/util/InterruptiveSleepManager' +import { contributionTransaction } from '@/apis/dltConnector' const db = AppDatabase.getInstance() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.ContributionResolver`) @@ -436,11 +438,13 @@ export class ContributionResolver { const logger = createLogger() logger.addContext('contribution', id) + let transaction: DbTransaction + let dltTransactionPromise: Promise // acquire lock const releaseLock = await TRANSACTIONS_LOCK.acquire() try { const clientTimezoneOffset = getClientTimezoneOffset(context) - const contribution = await DbContribution.findOne({ where: { id } }) + const contribution = await DbContribution.findOne({ where: { id }, relations: {user: {emailContact: true}} }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -450,18 +454,18 @@ export class ContributionResolver { if (contribution.contributionStatus === 'DENIED') { throw new LogError('Contribution already denied', id) } + const moderatorUser = getUser(context) if (moderatorUser.id === contribution.userId) { throw new LogError('Moderator can not confirm own contribution') } - const user = await DbUser.findOneOrFail({ - where: { id: contribution.userId }, - withDeleted: true, - relations: ['emailContact'], - }) + const user = contribution.user if (user.deletedAt) { throw new LogError('Can not confirm contribution since the user was deleted') } + const receivedCallDate = new Date() + dltTransactionPromise = contributionTransaction(contribution, moderatorUser, receivedCallDate) + const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false) validateContribution( creations, @@ -469,8 +473,7 @@ export class ContributionResolver { contribution.contributionDate, clientTimezoneOffset, ) - - const receivedCallDate = new Date() + const queryRunner = db.getDataSource().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED') @@ -491,7 +494,7 @@ export class ContributionResolver { } newBalance = newBalance.add(contribution.amount.toString()) - const transaction = new DbTransaction() + transaction = new DbTransaction() transaction.typeId = TransactionTypeId.CREATION transaction.memo = contribution.memo transaction.userId = contribution.userId @@ -509,7 +512,7 @@ export class ContributionResolver { transaction.balanceDate = receivedCallDate transaction.decay = decay ? decay.decay : new Decimal(0) transaction.decayStart = decay ? decay.start : null - await queryRunner.manager.insert(DbTransaction, transaction) + transaction = await queryRunner.manager.save(DbTransaction, transaction) contribution.confirmedAt = receivedCallDate contribution.confirmedBy = moderatorUser.id @@ -519,9 +522,6 @@ export class ContributionResolver { await queryRunner.commitTransaction() - // notify dlt-connector loop for new work - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - logger.info('creation commited successfuly.') await sendContributionConfirmedEmail({ firstName: user.firstName, @@ -547,6 +547,16 @@ export class ContributionResolver { } finally { releaseLock() } + // update transaction id in dlt transaction tables + // wait for finishing transaction by dlt-connector/hiero + const startTime = new Date() + const dltTransaction = await dltTransactionPromise + if(dltTransaction) { + dltTransaction.transactionId = transaction.id + await dltTransaction.save() + } + const endTime = new Date() + logger.debug(`dlt-connector contribution finished in ${endTime.getTime() - startTime.getTime()} ms`) return true } diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index b14ef2a4e..33d34d928 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -2,6 +2,7 @@ import { AppDatabase, countOpenPendingTransactions, Community as DbCommunity, + DltTransaction as DbDltTransaction, PendingTransaction as DbPendingTransaction, Transaction as dbTransaction, TransactionLink as dbTransactionLink, @@ -54,6 +55,7 @@ import { } from './util/processXComSendCoins' import { storeForeignUser } from './util/storeForeignUser' import { transactionLinkSummary } from './util/transactionLinkSummary' +import { transferTransaction } from '@/apis/dltConnector' const db = AppDatabase.getInstance() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionResolver`) @@ -66,6 +68,12 @@ export const executeTransaction = async ( logger: Logger, transactionLink?: dbTransactionLink | null, ): Promise => { + const receivedCallDate = new Date() + let dltTransactionPromise: Promise = Promise.resolve(null) + if (!transactionLink) { + dltTransactionPromise = transferTransaction(sender, recipient, amount.toString(), memo, receivedCallDate) + } + // acquire lock const releaseLock = await TRANSACTIONS_LOCK.acquire() @@ -82,8 +90,7 @@ export const executeTransaction = async ( throw new LogError('Sender and Recipient are the same', sender.id) } - // validate amount - const receivedCallDate = new Date() + // validate amount const sendBalance = await calculateBalance( sender.id, amount.mul(-1), @@ -163,7 +170,12 @@ export const executeTransaction = async ( } await queryRunner.commitTransaction() - logger.info(`commit Transaction successful...`) + // update dltTransaction with transactionId + const dltTransaction = await dltTransactionPromise + if (dltTransaction) { + dltTransaction.transactionId = transactionSend.id + await dltTransaction.save() + } await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount) @@ -179,8 +191,9 @@ export const executeTransaction = async ( } finally { await queryRunner.release() } + // notify dlt-connector loop for new work - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) + // InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) await sendTransactionReceivedEmail({ firstName: recipient.firstName, lastName: recipient.lastName, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 2e6667802..385811dba 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -1,6 +1,7 @@ import { AppDatabase, ContributionLink as DbContributionLink, + DltTransaction as DbDltTransaction, TransactionLink as DbTransactionLink, User as DbUser, UserContact as DbUserContact, @@ -85,10 +86,6 @@ import { Context, getClientTimezoneOffset, getUser } from '@/server/context' import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' import { durationInMinutesFromDates, getTimeDurationObject, printTimeDuration } from '@/util/time' -import { - InterruptiveSleepManager, - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, -} from '@/util/InterruptiveSleepManager' import { delay } from '@/util/utilities' import random from 'random-bigint' @@ -108,6 +105,7 @@ import { deleteUserRole, setUserRole } from './util/modifyUserRole' import { sendUserToGms } from './util/sendUserToGms' import { syncHumhub } from './util/syncHumhub' import { validateAlias } from 'core' +import { registerAddressTransaction } from '@/apis/dltConnector' const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] const DEFAULT_LANGUAGE = 'de' @@ -391,6 +389,7 @@ export class UserResolver { if (homeCom.communityUuid) { dbUser.communityUuid = homeCom.communityUuid } + dbUser.gradidoID = gradidoID dbUser.firstName = firstName dbUser.lastName = lastName @@ -401,8 +400,11 @@ export class UserResolver { dbUser.alias = alias } dbUser.publisherId = publisherId ?? 0 - dbUser.passwordEncryptionType = PasswordEncryptionType.NO_PASSWORD - logger.debug('new dbUser', new UserLoggingView(dbUser)) + dbUser.passwordEncryptionType = PasswordEncryptionType.NO_PASSWORD + + if(logger.isDebugEnabled()) { + logger.debug('new dbUser', new UserLoggingView(dbUser)) + } if (redeemCode) { if (redeemCode.match(/^CL-/)) { const contributionLink = await DbContributionLink.findOne({ @@ -438,7 +440,7 @@ export class UserResolver { dbUser.emailContact = emailContact dbUser.emailId = emailContact.id - await queryRunner.manager.save(dbUser).catch((error) => { + dbUser = await queryRunner.manager.save(dbUser).catch((error) => { throw new LogError('Error while updating dbUser', error) }) @@ -470,6 +472,8 @@ export class UserResolver { } finally { await queryRunner.release() } + // register user into blockchain + const dltTransactionPromise = registerAddressTransaction(dbUser, homeCom) logger.info('createUser() successful...') if (CONFIG.HUMHUB_ACTIVE) { let spaceId: number | null = null @@ -483,9 +487,6 @@ export class UserResolver { } } - // notify dlt-connector loop for new work - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - if (redeemCode) { eventRegisterRedeem.affectedUser = dbUser eventRegisterRedeem.actingUser = dbUser @@ -509,6 +510,11 @@ export class UserResolver { } } } + // wait for finishing dlt transaction + const startTime = new Date() + await dltTransactionPromise + const endTime = new Date() + logger.info(`dlt-connector register address finished in ${endTime.getTime() - startTime.getTime()} ms`) return new User(dbUser) } diff --git a/backend/src/index.ts b/backend/src/index.ts index a810b64a9..8a46cbb35 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -24,7 +24,7 @@ async function main() { // task is running the whole time for transmitting transaction via dlt-connector to iota // can be notified with InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) // that a new transaction or user was stored in db - void sendTransactionsToDltConnector() + // void sendTransactionsToDltConnector() void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 05852adda..93b3943c1 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -20,7 +20,7 @@ "log4js": "^6.9.1", "typescript": "^5.8.3", "uuid": "^8.3.2", - "valibot": "^1.1.0", + "valibot": "1.1.0", }, }, }, diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 26762c39e..bb7269703 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -33,7 +33,7 @@ "log4js": "^6.9.1", "typescript": "^5.8.3", "uuid": "^8.3.2", - "valibot": "^1.1.0" + "valibot": "1.1.0" }, "engines": { "node": ">=18" diff --git a/dlt-connector/src/client/backend/community.schema.test.ts b/dlt-connector/src/client/backend/community.schema.test.ts index e56056377..180ab9d5a 100644 --- a/dlt-connector/src/client/backend/community.schema.test.ts +++ b/dlt-connector/src/client/backend/community.schema.test.ts @@ -11,12 +11,14 @@ describe('community.schema', () => { uuid: '4f28e081-5c39-4dde-b6a4-3bde71de8d65', hieroTopicId: '0.0.4', foreign: false, + name: 'Test', creationDate: '2021-01-01', }), ).toEqual({ hieroTopicId: v.parse(hieroIdSchema, '0.0.4'), uuid: v.parse(uuidv4Schema, '4f28e081-5c39-4dde-b6a4-3bde71de8d65'), foreign: false, + name: 'Test', creationDate: new Date('2021-01-01'), }) }) diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 9c48800d8..0815437ef 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -2,10 +2,8 @@ import { AccountBalance, AccountBalanceQuery, Client, - Key, LocalProvider, PrivateKey, - Timestamp, TopicCreateTransaction, TopicId, TopicInfoQuery, @@ -59,6 +57,7 @@ export class HieroClient { topicId: HieroId, transaction: GradidoTransaction, ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { + let startTime = new Date() this.logger.addContext('topicId', topicId.toString()) const serializedTransaction = transaction.getSerializedTransaction() if (!serializedTransaction) { @@ -69,13 +68,27 @@ export class HieroClient { topicId, message: serializedTransaction.data(), }).freezeWithSigner(this.wallet) + let endTime = new Date() + this.logger.info(`prepare message, until freeze, cost: ${endTime.getTime() - startTime.getTime()}ms`) + startTime = new Date() const signedHieroTransaction = await hieroTransaction.signWithSigner(this.wallet) + endTime = new Date() + this.logger.info(`sign message, cost: ${endTime.getTime() - startTime.getTime()}ms`) + startTime = new Date() const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) + endTime = new Date() + this.logger.info(`send message, cost: ${endTime.getTime() - startTime.getTime()}ms`) + startTime = new Date() const sendReceipt = await sendResponse.getReceiptWithSigner(this.wallet) + endTime = new Date() + this.logger.info(`get receipt, cost: ${endTime.getTime() - startTime.getTime()}ms`) this.logger.info( `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, ) + startTime = new Date() const record = await sendResponse.getRecordWithSigner(this.wallet) + endTime = new Date() + this.logger.info(`get record, cost: ${endTime.getTime() - startTime.getTime()}ms`) this.logger.info(`message sent, cost: ${record.transactionFee.toString()}`) return { receipt: sendReceipt, response: sendResponse } } diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 1563d4b53..c64dda299 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -1,10 +1,10 @@ import { MemoryBlock } from 'gradido-blockchain-js' import { ParameterError } from '../errors' -import { IdentifierAccount } from '../schemas/account.schema' +import { IdentifierKeyPair } from '../schemas/account.schema' import { HieroId } from '../schemas/typeGuard.schema' export class KeyPairIdentifierLogic { - public constructor(public identifier: IdentifierAccount) {} + public constructor(public identifier: IdentifierKeyPair) {} isCommunityKeyPair(): boolean { return !this.identifier.seed && !this.identifier.account @@ -91,8 +91,8 @@ export class KeyPairIdentifierLogic { if (!this.identifier.account?.userUuid || !this.identifier.communityTopicId) { throw new ParameterError('userUuid and/or communityTopicId is undefined') } - const resultHexString = + const resultString = this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') - return MemoryBlock.fromHex(resultHexString).calculateHash().convertToHex() + return new MemoryBlock(resultString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index e2eb30a8a..afd517069 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -7,7 +7,6 @@ import { BackendClient } from './client/backend/BackendClient' import { GradidoNodeClient } from './client/GradidoNode/GradidoNodeClient' import { HieroClient } from './client/hiero/HieroClient' import { CONFIG } from './config' -import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' import { SendToHieroContext } from './interactions/sendToHiero/SendToHiero.context' import { KeyPairCacheManager } from './KeyPairCacheManager' import { Community, communitySchema } from './schemas/transaction.schema' diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts new file mode 100644 index 000000000..7c7103d94 --- /dev/null +++ b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts @@ -0,0 +1,99 @@ +import { describe, it, expect, mock, beforeAll, afterAll } from 'bun:test' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairCalculation } from './KeyPairCalculation.context' +import { parse } from 'valibot' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { KeyPairCacheManager } from '../../KeyPairCacheManager' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { identifierKeyPairSchema } from '../../schemas/account.schema' +/* +// Mock JsonRpcClient +const mockRpcCall = mock((params) => { + console.log('mockRpcCall', params) + return { + isSuccess: () => false, + isError: () => true, + error: { + code: GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND + } + } +}) +const mockRpcCallResolved = mock() + +mock.module('../../utils/network', () => ({ + isPortOpenRetry: async () => true, +})) + +mock.module('jsonrpc-ts-client', () => { + return { + default: class MockJsonRpcClient { + constructor() {} + exec = mockRpcCall + }, + } +}) +*/ + +mock.module('../../KeyPairCacheManager', () => { + let homeCommunityTopicId: HieroId | undefined + return { + KeyPairCacheManager: { + getInstance: () => ({ + setHomeCommunityTopicId: (topicId: HieroId) => { + homeCommunityTopicId = topicId + }, + getHomeCommunityTopicId: () => homeCommunityTopicId, + getKeyPair: (key: string, create: () => KeyPairEd25519) => { + return create() + }, + }), + }, + } +}) + +mock.module('../../config', () => ({ + CONFIG: { + HOME_COMMUNITY_SEED: MemoryBlock.fromHex('0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7'), + }, +})) + +const topicId = '0.0.21732' +const userUuid = 'aa25cf6f-2879-4745-b2ea-6d3c37fb44b0' + +console.log('userUuid', userUuid) + +afterAll(() => { + mock.restore() +}) + +describe('KeyPairCalculation', () => { + beforeAll(() => { + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) + }) + it('community key pair', async () => { + const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { communityTopicId: topicId })) + const keyPair = await KeyPairCalculation(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe('7bcb0d0ad26d3f7ba597716c38a570220cece49b959e57927ee0c39a5a9c3adf') + }) + it('user key pair', async () => { + const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { + communityTopicId: topicId, + account: { userUuid } + })) + expect(identifier.isAccountKeyPair()).toBe(false) + expect(identifier.isUserKeyPair()).toBe(true) + const keyPair = await KeyPairCalculation(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe('d61ae86c262fc0b5d763a8f41a03098fae73a7649a62aac844378a0eb0055921') + }) + + it('account key pair', async () => { + const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { + communityTopicId: topicId, + account: { userUuid, accountNr: 1 } + })) + expect(identifier.isAccountKeyPair()).toBe(true) + expect(identifier.isUserKeyPair()).toBe(false) + const keyPair = await KeyPairCalculation(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe('6cffb0ee0b20dae828e46f2e003f78ac57b85e7268e587703932f06e1b2daee4') + }) +}) diff --git a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts index 834f813c2..fd70682ea 100644 --- a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts @@ -21,7 +21,12 @@ export class CreationTransactionRole extends AbstractTransactionRole { private readonly creationTransaction: CreationTransaction constructor(transaction: Transaction) { super() - this.creationTransaction = parse(creationTransactionSchema, transaction) + try { + this.creationTransaction = parse(creationTransactionSchema, transaction) + } catch (error) { + console.error('creation: invalid transaction', JSON.stringify(error, null, 2)) + throw new Error('creation: invalid transaction') + } this.homeCommunityTopicId = KeyPairCacheManager.getInstance().getHomeCommunityTopicId() if ( this.homeCommunityTopicId !== this.creationTransaction.user.communityTopicId || diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts new file mode 100644 index 000000000..032ec5eec --- /dev/null +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from 'bun:test' +import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' +import { parse } from 'valibot' +import { + transactionSchema, +} from '../../schemas/transaction.schema' +import { hieroIdSchema } from '../../schemas/typeGuard.schema' +import { InteractionToJson, InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' + +const userUuid = '408780b2-59b3-402a-94be-56a4f4f4e8ec' +const transaction = { + user: { + communityTopicId: '0.0.21732', + account: { + userUuid, + accountNr: 0, + }, + }, + type: 'REGISTER_ADDRESS', + accountType: 'COMMUNITY_HUMAN', + createdAt: '2022-01-01T00:00:00.000Z', +} + +describe('RegisterAddressTransaction.role', () => { + it('get correct prepared builder', async () => { + const registerAddressTransactionRole = new RegisterAddressTransactionRole(parse(transactionSchema, transaction)) + expect(registerAddressTransactionRole.getSenderCommunityTopicId()).toBe(parse(hieroIdSchema, '0.0.21732')) + expect(() => registerAddressTransactionRole.getRecipientCommunityTopicId()).toThrow() + const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() + const gradidoTransaction = builder.build() + expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() + const json = JSON.parse(new InteractionToJson(gradidoTransaction).run()) + expect(json.bodyBytes.json.registerAddress.nameHash).toBe('bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08') + }) +}) \ No newline at end of file diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index 64076b920..32f78bac1 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -34,19 +34,15 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const communityKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic({ - communityTopicId: this.registerAddressTransaction.user.communityTopicId, - }), - ) - const accountKeyPairIdentifier = this.registerAddressTransaction.user + const communityTopicId = this.registerAddressTransaction.user.communityTopicId + const communityKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic({ communityTopicId })) + const keyPairIdentifier = this.registerAddressTransaction.user // when accountNr is 0 it is the user account - const userKeyPairIdentifier = accountKeyPairIdentifier - userKeyPairIdentifier.account.accountNr = 0 - - const userKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(userKeyPairIdentifier)) + keyPairIdentifier.account.accountNr = 0 + const userKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(keyPairIdentifier)) + keyPairIdentifier.account.accountNr = 1 const accountKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(accountKeyPairIdentifier), + new KeyPairIdentifierLogic(keyPairIdentifier), ) builder diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 996be0d10..8fde79267 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -58,28 +58,25 @@ export async function SendToHieroContext( // choose correct role based on transaction type and input type const chooseCorrectRole = (input: Transaction | Community): AbstractTransactionRole => { - const transactionParsingResult = safeParse(transactionSchema, input) const communityParsingResult = safeParse(communitySchema, input) - if (transactionParsingResult.success) { - const transaction = transactionParsingResult.output - switch (transaction.type) { - case InputTransactionType.GRADIDO_CREATION: - return new CreationTransactionRole(transaction) - case InputTransactionType.GRADIDO_TRANSFER: - return new TransferTransactionRole(transaction) - case InputTransactionType.REGISTER_ADDRESS: - return new RegisterAddressTransactionRole(transaction) - case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: - return new DeferredTransferTransactionRole(transaction) - case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: - return new RedeemDeferredTransferTransactionRole(transaction) - default: - throw new Error('not supported transaction type: ' + transaction.type) - } - } else if (communityParsingResult.success) { + if (communityParsingResult.success) { return new CommunityRootTransactionRole(communityParsingResult.output) - } else { - throw new Error('not expected input') + } + + const transaction = input as Transaction + switch (transaction.type) { + case InputTransactionType.GRADIDO_CREATION: + return new CreationTransactionRole(transaction) + case InputTransactionType.GRADIDO_TRANSFER: + return new TransferTransactionRole(transaction) + case InputTransactionType.REGISTER_ADDRESS: + return new RegisterAddressTransactionRole(transaction) + case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: + return new DeferredTransferTransactionRole(transaction) + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + return new RedeemDeferredTransferTransactionRole(transaction) + default: + throw new Error('not supported transaction type: ' + transaction.type) } } diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts index 7be2cd4f2..d1dbb4802 100644 --- a/dlt-connector/src/schemas/account.schema.ts +++ b/dlt-connector/src/schemas/account.schema.ts @@ -11,18 +11,22 @@ export type IdentifierSeed = v.InferOutput // identifier for gradido community accounts, inside a community export const identifierCommunityAccountSchema = v.object({ userUuid: uuidv4Schema, - accountNr: v.nullish(v.number('expect number type'), 0), + accountNr: v.optional(v.number('expect number type'), 0), }) export type IdentifierCommunityAccount = v.InferOutput +export const identifierKeyPairSchema = v.object({ + communityTopicId: hieroIdSchema, + account: v.optional(identifierCommunityAccountSchema), + seed: v.optional(identifierSeedSchema), +}) +export type IdentifierKeyPairInput = v.InferInput +export type IdentifierKeyPair = v.InferOutput + // identifier for gradido account, including the community uuid export const identifierAccountSchema = v.pipe( - v.object({ - communityTopicId: hieroIdSchema, - account: v.nullish(identifierCommunityAccountSchema, undefined), - seed: v.nullish(identifierSeedSchema, undefined), - }), + identifierKeyPairSchema, v.custom((value: any) => { const setFieldsCount = Number(value.seed !== undefined) + Number(value.account !== undefined) if (setFieldsCount !== 1) { diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index 61f485db6..7d204dba5 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -1,4 +1,6 @@ import { beforeAll, describe, expect, it } from 'bun:test' +import { TypeBoxFromValibot } from '@sinclair/typemap' +import { TypeCompiler } from '@sinclair/typebox/compiler' import { randomBytes } from 'crypto' import { v4 as uuidv4 } from 'uuid' import { parse } from 'valibot' @@ -13,7 +15,9 @@ import { Uuidv4, uuidv4Schema, } from '../schemas/typeGuard.schema' -import { TransactionInput, transactionSchema } from './transaction.schema' +import { registerAddressTransactionSchema, TransactionInput, transactionSchema } from './transaction.schema' +import { AccountType } from '../enum/AccountType' +import { AddressType_COMMUNITY_HUMAN } from 'gradido-blockchain-js' const transactionLinkCode = (date: Date): string => { const time = date.getTime().toString(16) @@ -40,27 +44,54 @@ describe('transaction schemas', () => { memoString = 'TestMemo' memo = parse(memoSchema, memoString) }) - it('valid, register new user address', () => { - const registerAddress: TransactionInput = { - user: { - communityTopicId: topicString, - account: { userUuid: userUuidString }, - }, - type: InputTransactionType.REGISTER_ADDRESS, - createdAt: '2022-01-01T00:00:00.000Z', - } - expect(parse(transactionSchema, registerAddress)).toEqual({ - user: { - communityTopicId: topic, - account: { - userUuid, - accountNr: 0, + describe('register address', () => { + let registerAddress: TransactionInput + beforeAll(() => { + registerAddress = { + user: { + communityTopicId: topicString, + account: { userUuid: userUuidString }, }, - }, - type: registerAddress.type, - createdAt: new Date(registerAddress.createdAt), + type: InputTransactionType.REGISTER_ADDRESS, + accountType: AccountType.COMMUNITY_HUMAN, + createdAt: new Date().toISOString(), + } + }) + it('valid transaction schema', () => { + expect(parse(transactionSchema, registerAddress)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + type: registerAddress.type, + accountType: AccountType.COMMUNITY_HUMAN, + createdAt: new Date(registerAddress.createdAt), + }) + }) + it('valid register address schema', () => { + expect(parse(registerAddressTransactionSchema, registerAddress)).toEqual({ + user: { + communityTopicId: topic, + account: { + userUuid, + accountNr: 0, + }, + }, + accountType: AddressType_COMMUNITY_HUMAN, + createdAt: new Date(registerAddress.createdAt), + }) + }) + it('valid, transaction schema with typebox', () => { + // console.log(JSON.stringify(TypeBoxFromValibot(transactionSchema), null, 2)) + const TTransactionSchema = TypeBoxFromValibot(transactionSchema) + const check = TypeCompiler.Compile(TTransactionSchema) + expect(check.Check(registerAddress)).toBe(true) }) }) + it('valid, gradido transfer', () => { const gradidoTransfer: TransactionInput = { user: { diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index 4345ec901..7c1855ec8 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -5,7 +5,7 @@ import { identifierCommunityAccountSchema, identifierSeedSchema, } from './account.schema' -import { accountTypeSchema, addressTypeSchema, dateSchema } from './typeConverter.schema' +import { addressTypeSchema, dateSchema } from './typeConverter.schema' import { gradidoAmountSchema, hieroIdSchema, @@ -13,6 +13,7 @@ import { timeoutDurationSchema, uuidv4Schema, } from './typeGuard.schema' +import { AccountType } from '../enum/AccountType' /** * Schema for community, for creating new CommunityRoot Transaction on gradido blockchain @@ -29,14 +30,14 @@ export type Community = v.InferOutput export const transactionSchema = v.object({ user: identifierAccountSchema, - linkedUser: v.nullish(identifierAccountSchema, undefined), - amount: v.nullish(gradidoAmountSchema, undefined), - memo: v.nullish(memoSchema, undefined), + linkedUser: v.optional(identifierAccountSchema), + amount: v.optional(gradidoAmountSchema), + memo: v.optional(memoSchema), type: v.enum(InputTransactionType), createdAt: dateSchema, - targetDate: v.nullish(dateSchema, undefined), - timeoutDuration: v.nullish(timeoutDurationSchema, undefined), - accountType: v.nullish(accountTypeSchema, undefined), + targetDate: v.optional(dateSchema), + timeoutDuration: v.optional(timeoutDurationSchema), + accountType: v.optional(v.enum(AccountType)), }) export type TransactionInput = v.InferInput diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index 71cae3619..dd8944247 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -1,6 +1,8 @@ +import { Static, TypeBoxFromValibot } from '@sinclair/typemap' +import { TypeCompiler } from '@sinclair/typebox/compiler' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' -import { AddressType_COMMUNITY_AUF, AddressType_COMMUNITY_PROJECT } from 'gradido-blockchain-js' +import { AddressType_COMMUNITY_AUF } from 'gradido-blockchain-js' import * as v from 'valibot' import { AccountType } from '../enum/AccountType' import { @@ -23,6 +25,27 @@ describe('basic.schema', () => { it('invalid date', () => { expect(() => v.parse(dateSchema, 'invalid date')).toThrow(new Error('invalid date')) }) + it('with type box', () => { + // Derive TypeBox Schema from the Valibot Schema + const DateSchema = TypeBoxFromValibot(dateSchema) + + // Build the compiler + const check = TypeCompiler.Compile(DateSchema) + + // Valid value (String) + expect(check.Check('2021-01-01T10:10:00.000Z')).toBe(true) + + // typebox cannot use valibot custom validation and transformations, it will check only the input types + expect(check.Check('invalid date')).toBe(true) + + // Type inference (TypeScript) + type DateType = Static + const validDate: DateType = '2021-01-01T10:10:00.000Z' + const validDate2: DateType = new Date('2021-01-01') + + // @ts-expect-error + const invalidDate: DateType = 123 // should fail in TS + }) }) describe('AddressType and AccountType', () => { @@ -46,6 +69,22 @@ describe('basic.schema', () => { const accountType = v.parse(accountTypeSchema, AddressType_COMMUNITY_AUF) expect(accountType).toBe(AccountType.COMMUNITY_AUF) }) + it('addressType with type box', () => { + const AddressTypeSchema = TypeBoxFromValibot(addressTypeSchema) + const check = TypeCompiler.Compile(AddressTypeSchema) + expect(check.Check(AccountType.COMMUNITY_AUF)).toBe(true) + // type box will throw an error, because it cannot handle valibots custom validation + expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + expect(() => check.Check('invalid')).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + }) + it('accountType with type box', () => { + const AccountTypeSchema = TypeBoxFromValibot(accountTypeSchema) + const check = TypeCompiler.Compile(AccountTypeSchema) + expect(check.Check(AccountType.COMMUNITY_AUF)).toBe(true) + // type box will throw an error, because it cannot handle valibots custom validation + expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + expect(() => check.Check('invalid')).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + }) }) it('confirmedTransactionSchema', () => { diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 4410b54be..2e4811c11 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -47,8 +47,8 @@ export const addressTypeSchema = v.pipe( */ export const accountTypeSchema = v.pipe( v.union([ - v.custom(isAddressType, 'expect AddressType'), v.enum(AccountType, 'expect AccountType'), + v.custom(isAddressType, 'expect AddressType'), ]), v.transform((value) => toAccountType(value)), ) diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts index b084e8531..d580abe3a 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -168,11 +168,21 @@ declare const validTimeoutDuration: unique symbol export type TimeoutDuration = DurationSeconds & { [validTimeoutDuration]: true } export const timeoutDurationSchema = v.pipe( - v.number('expect number type'), - v.minValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MIN, 'expect number >= 1 hour'), - v.maxValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MAX, 'expect number <= 3 months'), - v.transform( - (input: number) => new DurationSeconds(input) as TimeoutDuration, + v.union([ + v.pipe( + v.number('expect number type'), + v.minValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MIN, 'expect number >= 1 hour'), + v.maxValue(LINKED_TRANSACTION_TIMEOUT_DURATION_MAX, 'expect number <= 3 months'), + ), + v.instance(DurationSeconds, 'expect DurationSeconds type'), + ]), + v.transform( + (input: number | DurationSeconds) => { + if (input instanceof DurationSeconds) { + return input as TimeoutDuration + } + return new DurationSeconds(input) as TimeoutDuration + }, ), ) @@ -200,8 +210,16 @@ declare const validGradidoAmount: unique symbol export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true } export const gradidoAmountSchema = v.pipe( - amountSchema, - v.transform( - (input: Amount) => GradidoUnit.fromString(input) as GradidoAmount, + v.union([ + amountSchema, + v.instance(GradidoUnit, 'expect GradidoUnit type'), + ]), + v.transform( + (input: Amount | GradidoUnit) => { + if (input instanceof GradidoUnit) { + return input as GradidoAmount + } + return GradidoUnit.fromString(input) as GradidoAmount + }, ), ) diff --git a/dlt-connector/src/server/index.test.ts b/dlt-connector/src/server/index.test.ts new file mode 100644 index 000000000..f3a9aed7d --- /dev/null +++ b/dlt-connector/src/server/index.test.ts @@ -0,0 +1,75 @@ +import { appRoutes } from '.' +import { describe, it, expect, beforeAll, mock } from 'bun:test' +import { KeyPairCacheManager } from '../KeyPairCacheManager' +import { hieroIdSchema } from '../schemas/typeGuard.schema' +import { parse } from 'valibot' +import { HieroId } from '../schemas/typeGuard.schema' +import { GradidoTransaction, KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' + +const userUuid = '408780b2-59b3-402a-94be-56a4f4f4e8ec' + +mock.module('../KeyPairCacheManager', () => { + let homeCommunityTopicId: HieroId | undefined + return { + KeyPairCacheManager: { + getInstance: () => ({ + setHomeCommunityTopicId: (topicId: HieroId) => { + homeCommunityTopicId = topicId + }, + getHomeCommunityTopicId: () => homeCommunityTopicId, + getKeyPair: (key: string, create: () => KeyPairEd25519) => { + return create() + }, + }), + }, + } +}) + +mock.module('../client/hiero/HieroClient', () => ({ + HieroClient: { + getInstance: () => ({ + sendMessage: (topicId: HieroId, transaction: GradidoTransaction) => { + return { receipt: { status: '0.0.21732' }, response: { transactionId: '0.0.6566984@1758029639.561157605' } } + }, + }), + }, +})) + +mock.module('../config', () => ({ + CONFIG: { + HOME_COMMUNITY_SEED: MemoryBlock.fromHex('0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7'), + }, +})) + +beforeAll(() => { + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) +}) + +describe('Server', () => { + it('send register address transaction', async () => { + const transaction = { + user: { + communityTopicId: '0.0.21732', + account: { + userUuid, + accountNr: 0, + }, + }, + type: 'REGISTER_ADDRESS', + accountType: 'COMMUNITY_HUMAN', + createdAt: '2022-01-01T00:00:00.000Z', + } + const response = await appRoutes.handle(new Request('http://localhost/sendTransaction', { + method: 'POST', + body: JSON.stringify(transaction), + headers: { + 'Content-Type': 'application/json', + }, + })) + if (response.status !== 200) { + console.log(await response.text()) + } + expect(response.status).toBe(200) + expect(await response.text()).toBe('0.0.6566984@1758029639.561157605') + }) +}) diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 3aa13dcac..b8aa44fd3 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,6 +1,6 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' import { Type } from '@sinclair/typebox' -import { Elysia, status } from 'elysia' +import { Elysia, status, t } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { parse } from 'valibot' @@ -11,7 +11,7 @@ import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCa import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' import { IdentifierAccount, identifierAccountSchema } from '../schemas/account.schema' import { transactionSchema } from '../schemas/transaction.schema' -import { hieroTransactionIdSchema } from '../schemas/typeGuard.schema' +import { hieroIdSchema, hieroTransactionIdSchema } from '../schemas/typeGuard.schema' import { accountIdentifierSeedSchema, accountIdentifierUserSchema, @@ -48,29 +48,22 @@ export const appRoutes = new Elysia() .post( '/sendTransaction', async ({ body }) => { - console.log("sendTransaction was called") - return "0.0.123" - console.log(body) - console.log(parse(transactionSchema, body)) - const transaction = parse(transactionSchema, body) - return await SendToHieroContext(transaction) + try { + const hieroTransactionId = await SendToHieroContext(parse(transactionSchema, body)) + console.log('server will return:', hieroTransactionId) + return { transactionId: hieroTransactionId } + } catch (e) { + if (e instanceof TypeError) { + console.log(`message: ${e.message}, stack: ${e.stack}`) + } + console.log(e) + throw status(500, e) + } }, // validation schemas { - // body: TypeBoxFromValibot(transactionSchema), - body: Type.Object({ - user: Type.Object({ - communityUser: Type.Object({ - uuid: Type.String({ format: 'uuid' }), - accountNr: Type.Optional(Type.String()), // optional/undefined - }), - communityUuid: Type.String({ format: 'uuid' }), - }), - createdAt: Type.String({ format: 'date-time' }), - accountType: Type.Literal('COMMUNITY_HUMAN'), - type: Type.Literal('REGISTER_ADDRESS'), - }) - // response: TypeBoxFromValibot(hieroTransactionIdSchema), + body: TypeBoxFromValibot(transactionSchema), + response: t.Object({ transactionId: TypeBoxFromValibot(hieroTransactionIdSchema) }), }, ) From 4e3d119f1249d6f95060856ad224feb612af9124 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 24 Sep 2025 16:25:43 +0200 Subject: [PATCH 034/226] direct sending transaction types to dlt --- backend/src/apis/dltConnector/index.ts | 62 +++++++++++++++- .../dltConnector/model/TransactionDraft.ts | 55 ++++++++++++++- .../graphql/resolver/ContributionResolver.ts | 32 ++++----- .../resolver/TransactionLinkResolver.ts | 67 +++++++++++++----- .../graphql/resolver/TransactionResolver.ts | 30 ++++---- backend/src/graphql/resolver/const/const.ts | 1 + backend/src/util/InterruptiveSleep.ts | 2 +- .../src/logging/UserContactLogging.view.ts | 4 +- database/src/logging/UserLogging.view.ts | 11 +-- database/src/logging/UserRoleLogging.view.ts | 4 +- database/src/queries/events.ts | 19 +++++ database/src/queries/index.ts | 1 + database/src/queries/user.ts | 7 ++ dlt-connector/bun.lock | 6 ++ dlt-connector/src/client/hiero/HieroClient.ts | 70 ++++++++++++------- dlt-connector/src/index.ts | 31 ++++++++ .../sendToHiero/SendToHiero.context.ts | 10 +-- 17 files changed, 323 insertions(+), 89 deletions(-) create mode 100644 database/src/queries/events.ts diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index 7780006e9..671c88297 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -7,8 +7,12 @@ import { Community as DbCommunity, Contribution as DbContribution, DltTransaction as DbDltTransaction, + TransactionLink as DbTransactionLink, User as DbUser, - getHomeCommunity, + getCommunityByUuid, + getHomeCommunity, + getUserById, + UserLoggingView, } from 'database' import { TransactionDraft } from './model/TransactionDraft' @@ -92,7 +96,15 @@ export async function transferTransaction( memo: string, createdAt: Date ): Promise { - + // load community if not already loaded, maybe they are remote communities + if (!senderUser.community) { + senderUser.community = await getCommunityByUuid(senderUser.communityUuid) + } + if (!recipientUser.community) { + recipientUser.community = await getCommunityByUuid(recipientUser.communityUuid) + } + logger.info(`sender user: ${new UserLoggingView(senderUser)}`) + logger.info(`recipient user: ${new UserLoggingView(recipientUser)}`) const draft = TransactionDraft.createTransfer(senderUser, recipientUser, amount, memo, createdAt) if (draft && dltConnectorClient) { const clientResponse = dltConnectorClient.sendTransaction(draft) @@ -104,4 +116,50 @@ export async function transferTransaction( return null } +export async function deferredTransferTransaction(senderUser: DbUser, transactionLink: DbTransactionLink) +: Promise { + // load community if not already loaded + if (!senderUser.community) { + senderUser.community = await getCommunityByUuid(senderUser.communityUuid) + } + const draft = TransactionDraft.createDeferredTransfer(senderUser, transactionLink) + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = DltTransactionType.DEFERRED_TRANSFER + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + return await dltTransaction.save() + } + return null +} + +export async function redeemDeferredTransferTransaction(transactionLink: DbTransactionLink, amount: string, createdAt: Date, recipientUser: DbUser) +: Promise { + // load user and communities if not already loaded + if (!transactionLink.user) { + logger.debug('load sender user') + transactionLink.user = await getUserById(transactionLink.userId, true, false) + } + if (!transactionLink.user.community) { + logger.debug('load sender community') + transactionLink.user.community = await getCommunityByUuid(transactionLink.user.communityUuid) + } + if (!recipientUser.community) { + logger.debug('load recipient community') + recipientUser.community = await getCommunityByUuid(recipientUser.communityUuid) + } + logger.debug(`sender: ${new UserLoggingView(transactionLink.user)}`) + logger.debug(`recipient: ${new UserLoggingView(recipientUser)}`) + const draft = TransactionDraft.redeemDeferredTransfer(transactionLink, amount, createdAt, recipientUser) + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = DltTransactionType.REDEEM_DEFERRED_TRANSFER + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + return await dltTransaction.save() + } + return null +} + + diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 86f46a43b..5c40da289 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -3,10 +3,17 @@ import { AccountType } from '@dltConnector/enum/AccountType' import { TransactionType } from '@dltConnector/enum/TransactionType' import { AccountIdentifier } from './AccountIdentifier' -import { Community as DbCommunity, Contribution as DbContribution, User as DbUser } from 'database' +import { + Community as DbCommunity, + Contribution as DbContribution, + TransactionLink as DbTransactionLink, + User as DbUser +} from 'database' import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' +import { IdentifierSeed } from './IdentifierSeed' +import { CODE_VALID_DAYS_DURATION } from '@/graphql/resolver/const/const' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector.model.TransactionDraft`) @@ -21,7 +28,7 @@ export class TransactionDraft { createdAt: string // only for creation transaction targetDate?: string - // only for deferred transaction + // only for deferred transaction, duration in seconds timeoutDuration?: number // only for register address accountType?: AccountType @@ -75,4 +82,48 @@ export class TransactionDraft { draft.memo = memo return draft } + + static createDeferredTransfer(sendingUser: DbUser, transactionLink: DbTransactionLink) + : TransactionDraft | null { + if (!sendingUser.community) { + throw new Error(`missing community for user ${sendingUser.id}`) + } + const senderUserTopic = sendingUser.community.hieroTopicId + if (!senderUserTopic) { + throw new Error(`missing topicId for community ${sendingUser.community.id}`) + } + const draft = new TransactionDraft() + draft.user = new AccountIdentifier(senderUserTopic, new CommunityAccountIdentifier(sendingUser.gradidoID)) + draft.linkedUser = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER + draft.createdAt = transactionLink.createdAt.toISOString() + draft.amount = transactionLink.amount.toString() + draft.memo = transactionLink.memo + draft.timeoutDuration = CODE_VALID_DAYS_DURATION * 24 * 60 * 60 + return draft + } + + static redeemDeferredTransfer(transactionLink: DbTransactionLink, amount: string, createdAt: Date, recipientUser: DbUser): TransactionDraft | null { + if (!transactionLink.user.community) { + throw new Error(`missing community for user ${transactionLink.user.id}`) + } + if (!recipientUser.community) { + throw new Error(`missing community for user ${recipientUser.id}`) + } + const senderUserTopic = transactionLink.user.community.hieroTopicId + if (!senderUserTopic) { + throw new Error(`missing topicId for community ${transactionLink.user.community.id}`) + } + const recipientUserTopic = recipientUser.community.hieroTopicId + if (!recipientUserTopic) { + throw new Error(`missing topicId for community ${recipientUser.community.id}`) + } + const draft = new TransactionDraft() + draft.user = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.linkedUser = new AccountIdentifier(recipientUserTopic, new CommunityAccountIdentifier(recipientUser.gradidoID)) + draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER + draft.createdAt = createdAt.toISOString() + draft.amount = amount + return draft + } } \ No newline at end of file diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 7c31209e0..ac06f012e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -436,9 +436,6 @@ export class ContributionResolver { ): Promise { const logger = createLogger() logger.addContext('contribution', id) - - let transaction: DbTransaction - let dltTransactionPromise: Promise // acquire lock const releaseLock = await TRANSACTIONS_LOCK.acquire() try { @@ -463,8 +460,7 @@ export class ContributionResolver { throw new LogError('Can not confirm contribution since the user was deleted') } const receivedCallDate = new Date() - dltTransactionPromise = contributionTransaction(contribution, moderatorUser, receivedCallDate) - + const dltTransactionPromise = contributionTransaction(contribution, moderatorUser, receivedCallDate) const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false) validateContribution( creations, @@ -476,7 +472,6 @@ export class ContributionResolver { const queryRunner = db.getDataSource().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED') - const lastTransaction = await getLastTransaction(contribution.userId) logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined') @@ -493,7 +488,7 @@ export class ContributionResolver { } newBalance = newBalance.add(contribution.amount.toString()) - transaction = new DbTransaction() + let transaction = new DbTransaction() transaction.typeId = TransactionTypeId.CREATION transaction.memo = contribution.memo transaction.userId = contribution.userId @@ -520,7 +515,7 @@ export class ContributionResolver { await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution) await queryRunner.commitTransaction() - + logger.info('creation commited successfuly.') await sendContributionConfirmedEmail({ firstName: user.firstName, @@ -536,6 +531,17 @@ export class ContributionResolver { contribution.createdAt, ), }) + + // update transaction id in dlt transaction tables + // wait for finishing transaction by dlt-connector/hiero + const dltStartTime = new Date() + const dltTransaction = await dltTransactionPromise + if(dltTransaction) { + dltTransaction.transactionId = transaction.id + await dltTransaction.save() + } + const dltEndTime = new Date() + logger.debug(`dlt-connector contribution finished in ${dltEndTime.getTime() - dltStartTime.getTime()} ms`) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Creation was not successful', e) @@ -546,16 +552,6 @@ export class ContributionResolver { } finally { releaseLock() } - // update transaction id in dlt transaction tables - // wait for finishing transaction by dlt-connector/hiero - const startTime = new Date() - const dltTransaction = await dltTransactionPromise - if(dltTransaction) { - dltTransaction.transactionId = transaction.id - await dltTransaction.save() - } - const endTime = new Date() - logger.debug(`dlt-connector contribution finished in ${endTime.getTime() - startTime.getTime()} ms`) return true } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 624038c20..4521ce4ae 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -14,10 +14,13 @@ import { User } from '@model/User' import { QueryLinkResult } from '@union/QueryLinkResult' import { Decay, interpretEncryptedTransferArgs, TransactionTypeId } from 'core' import { - AppDatabase, Community as DbCommunity, Contribution as DbContribution, - ContributionLink as DbContributionLink, FederatedCommunity as DbFederatedCommunity, Transaction as DbTransaction, + AppDatabase, Contribution as DbContribution, + ContributionLink as DbContributionLink, FederatedCommunity as DbFederatedCommunity, + DltTransaction as DbDltTransaction, + Transaction as DbTransaction, TransactionLink as DbTransactionLink, User as DbUser, + findModeratorCreatingContributionLink, findTransactionLinkByCode, getHomeCommunity } from 'database' @@ -33,14 +36,10 @@ import { } from '@/event/Events' import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' -import { - InterruptiveSleepManager, - TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, -} from '@/util/InterruptiveSleepManager' import { calculateBalance } from '@/util/validate' import { fullName } from 'core' import { TRANSACTION_LINK_LOCK, TRANSACTIONS_LOCK } from 'database' -import { calculateDecay, decode, DisburseJwtPayloadType, encode, encryptAndSign, EncryptedJWEJwtPayloadType, RedeemJwtPayloadType, verify } from 'shared' +import { calculateDecay, decode, DisburseJwtPayloadType, encode, encryptAndSign, RedeemJwtPayloadType, verify } from 'shared' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { DisbursementClient as V1_0_DisbursementClient } from '@/federation/client/1_0/DisbursementClient' @@ -58,6 +57,8 @@ import { import { getUserCreation, validateContribution } from './util/creations' import { transactionLinkList } from './util/transactionLinkList' import { SignedTransferPayloadType } from 'shared' +import { contributionTransaction, deferredTransferTransaction, redeemDeferredTransferTransaction } from '@/apis/dltConnector' +import { CODE_VALID_DAYS_DURATION } from './const/const' const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionLinkResolver.${method}`) @@ -71,7 +72,7 @@ export const transactionLinkCode = (date: Date): string => { ) } -const CODE_VALID_DAYS_DURATION = 14 + const db = AppDatabase.getInstance() export const transactionLinkExpireDate = (date: Date): Date => { @@ -109,11 +110,20 @@ export class TransactionLinkResolver { transactionLink.code = transactionLinkCode(createdDate) transactionLink.createdAt = createdDate transactionLink.validUntil = validUntil + const dltTransactionPromise = deferredTransferTransaction(user, transactionLink) await DbTransactionLink.save(transactionLink).catch((e) => { throw new LogError('Unable to save transaction link', e) }) await EVENT_TRANSACTION_LINK_CREATE(user, transactionLink, amount) - + // wait for dlt transaction to be created + const startTime = Date.now() + const dltTransaction = await dltTransactionPromise + const endTime = Date.now() + createLogger('createTransactionLink').debug(`dlt transaction created in ${endTime - startTime} ms`) + if (dltTransaction) { + dltTransaction.transactionLinkId = transactionLink.id + await DbDltTransaction.save(dltTransaction) + } return new TransactionLink(transactionLink, new User(user)) } @@ -137,7 +147,6 @@ export class TransactionLinkResolver { user.id, ) } - if (transactionLink.redeemedBy) { throw new LogError('Transaction link already redeemed', transactionLink.redeemedBy) } @@ -146,7 +155,19 @@ export class TransactionLinkResolver { throw new LogError('Transaction link could not be deleted', e) }) + transactionLink.user = user + const dltTransactionPromise = redeemDeferredTransferTransaction(transactionLink, transactionLink.amount.toString(), transactionLink.deletedAt!, user) + await EVENT_TRANSACTION_LINK_DELETE(user, transactionLink) + // wait for dlt transaction to be created + const startTime = Date.now() + const dltTransaction = await dltTransactionPromise + const endTime = Date.now() + createLogger('deleteTransactionLink').debug(`dlt transaction created in ${endTime - startTime} ms`) + if (dltTransaction) { + dltTransaction.transactionLinkId = transactionLink.id + await DbDltTransaction.save(dltTransaction) + } return true } @@ -279,7 +300,7 @@ export class TransactionLinkResolver { throw new LogError('Contribution link has unknown cycle', contributionLink.cycle) } } - + const moderatorPromise = findModeratorCreatingContributionLink(contributionLink) const creations = await getUserCreation(user.id, clientTimezoneOffset) methodLogger.info('open creations', creations) validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset) @@ -293,6 +314,12 @@ export class TransactionLinkResolver { contribution.contributionType = ContributionType.LINK contribution.contributionStatus = ContributionStatus.CONFIRMED + let dltTransactionPromise: Promise = Promise.resolve(null) + const moderator = await moderatorPromise + if (moderator) { + dltTransactionPromise = contributionTransaction(contribution, moderator, now) + } + await queryRunner.manager.insert(DbContribution, contribution) const lastTransaction = await getLastTransaction(user.id) @@ -338,6 +365,17 @@ export class TransactionLinkResolver { contributionLink, contributionLink.amount, ) + if (dltTransactionPromise) { + const startTime = new Date() + const dltTransaction = await dltTransactionPromise + const endTime = new Date() + methodLogger.info(`dlt-connector transaction finished in ${endTime.getTime() - startTime.getTime()} ms`) + if (dltTransaction) { + dltTransaction.transactionId = transaction.id + await dltTransaction.save() + } + + } } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Creation from contribution link was not successful', e) @@ -346,10 +384,7 @@ export class TransactionLinkResolver { } } finally { releaseLock() - } - // notify dlt-connector loop for new work - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - + } return true } else { const now = new Date() @@ -399,8 +434,6 @@ export class TransactionLinkResolver { } finally { releaseLinkLock() } - // notify dlt-connector loop for new work - InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) return true } } diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 79b6eff5f..0b1d6d866 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -6,7 +6,9 @@ import { Transaction as dbTransaction, TransactionLink as dbTransactionLink, User as dbUser, - findUserByIdentifier + findUserByIdentifier, + TransactionLoggingView, + UserLoggingView } from 'database' import { Decimal } from 'decimal.js-light' import { Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' @@ -43,7 +45,7 @@ import { GdtResolver } from './GdtResolver' import { getCommunityName, isHomeCommunity } from './util/communities' import { getTransactionList } from './util/getTransactionList' import { transactionLinkSummary } from './util/transactionLinkSummary' -import { transferTransaction } from '@/apis/dltConnector' +import { transferTransaction, redeemDeferredTransferTransaction } from '@/apis/dltConnector' const db = AppDatabase.getInstance() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionResolver`) @@ -60,13 +62,15 @@ export const executeTransaction = async ( let dltTransactionPromise: Promise = Promise.resolve(null) if (!transactionLink) { dltTransactionPromise = transferTransaction(sender, recipient, amount.toString(), memo, receivedCallDate) + } else { + dltTransactionPromise = redeemDeferredTransferTransaction(transactionLink, amount.toString(), receivedCallDate, recipient) } // acquire lock const releaseLock = await TRANSACTIONS_LOCK.acquire() try { - logger.info('executeTransaction', amount, memo, sender, recipient) + logger.info('executeTransaction', memo) if (await countOpenPendingTransactions([sender.gradidoID, recipient.gradidoID]) > 0) { throw new LogError( @@ -85,7 +89,7 @@ export const executeTransaction = async ( receivedCallDate, transactionLink, ) - logger.debug(`calculated Balance=${sendBalance}`) + logger.debug(`calculated balance=${sendBalance?.balance.toString()} decay=${sendBalance?.decay.decay.toString()} lastTransactionId=${sendBalance?.lastTransactionId}`) if (!sendBalance) { throw new LogError('User has not enough GDD or amount is < 0', sendBalance) } @@ -144,7 +148,7 @@ export const executeTransaction = async ( // 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) + logger.debug('send Transaction updated', new TransactionLoggingView(transactionSend).toJSON()) if (transactionLink) { logger.info('transactionLink', transactionLink) @@ -158,21 +162,23 @@ export const executeTransaction = async ( } await queryRunner.commitTransaction() - // update dltTransaction with transactionId - const dltTransaction = await dltTransactionPromise - if (dltTransaction) { - dltTransaction.transactionId = transactionSend.id - await dltTransaction.save() - } await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount) - await EVENT_TRANSACTION_RECEIVE( recipient, sender, transactionReceive, transactionReceive.amount, ) + // update dltTransaction with transactionId + const startTime = new Date() + const dltTransaction = await dltTransactionPromise + const endTime = new Date() + logger.debug(`dlt-connector transaction finished in ${endTime.getTime() - startTime.getTime()} ms`) + if (dltTransaction) { + dltTransaction.transactionId = transactionSend.id + await dltTransaction.save() + } } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Transaction was not successful', e) diff --git a/backend/src/graphql/resolver/const/const.ts b/backend/src/graphql/resolver/const/const.ts index 8497ca6d5..8e0a0722e 100644 --- a/backend/src/graphql/resolver/const/const.ts +++ b/backend/src/graphql/resolver/const/const.ts @@ -12,3 +12,4 @@ export const MEMO_MAX_CHARS = 512 export const MEMO_MIN_CHARS = 5 export const DEFAULT_PAGINATION_PAGE_SIZE = 25 export const FRONTEND_CONTRIBUTIONS_ITEM_ANCHOR_PREFIX = 'contributionListItem-' +export const CODE_VALID_DAYS_DURATION = 14 \ No newline at end of file diff --git a/backend/src/util/InterruptiveSleep.ts b/backend/src/util/InterruptiveSleep.ts index dc8ed5ae0..86afcf9b5 100644 --- a/backend/src/util/InterruptiveSleep.ts +++ b/backend/src/util/InterruptiveSleep.ts @@ -1,4 +1,4 @@ -import { delay } from './utilities' +import { delay } from 'core' /** * Sleep, that can be interrupted diff --git a/database/src/logging/UserContactLogging.view.ts b/database/src/logging/UserContactLogging.view.ts index d80b17c67..4bd567cad 100644 --- a/database/src/logging/UserContactLogging.view.ts +++ b/database/src/logging/UserContactLogging.view.ts @@ -8,7 +8,7 @@ enum OptInType { } export class UserContactLoggingView extends AbstractLoggingView { - public constructor(private self: UserContact) { + public constructor(private self: UserContact, private showUser = true) { super() } @@ -16,7 +16,7 @@ export class UserContactLoggingView extends AbstractLoggingView { return { id: this.self.id, type: this.self.type, - user: this.self.user + user: this.showUser && this.self.user ? new UserLoggingView(this.self.user).toJSON() : { id: this.self.userId }, email: this.self.email?.substring(0, 3) + '...', diff --git a/database/src/logging/UserLogging.view.ts b/database/src/logging/UserLogging.view.ts index 1aa5e4407..84db8a6fe 100644 --- a/database/src/logging/UserLogging.view.ts +++ b/database/src/logging/UserLogging.view.ts @@ -4,6 +4,7 @@ import { ContributionLoggingView } from './ContributionLogging.view' import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' import { UserContactLoggingView } from './UserContactLogging.view' import { UserRoleLoggingView } from './UserRoleLogging.view' +import { CommunityLoggingView } from './CommunityLogging.view' enum PasswordEncryptionType { NO_PASSWORD = 0, @@ -21,10 +22,12 @@ export class UserLoggingView extends AbstractLoggingView { id: this.self.id, foreign: this.self.foreign, gradidoID: this.self.gradidoID, - communityUuid: this.self.communityUuid, + community: this.self.community + ? new CommunityLoggingView(this.self.community).toJSON() + : { id: this.self.communityUuid }, alias: this.self.alias?.substring(0, 3) + '...', emailContact: this.self.emailContact - ? new UserContactLoggingView(this.self.emailContact).toJSON() + ? new UserContactLoggingView(this.self.emailContact, false).toJSON() : { id: this.self.emailId }, firstName: this.self.firstName?.substring(0, 3) + '...', lastName: this.self.lastName?.substring(0, 3) + '...', @@ -35,7 +38,7 @@ export class UserLoggingView extends AbstractLoggingView { hideAmountGDD: this.self.hideAmountGDD, hideAmountGDT: this.self.hideAmountGDT, userRoles: this.self.userRoles - ? this.self.userRoles.map((userRole) => new UserRoleLoggingView(userRole).toJSON()) + ? this.self.userRoles.map((userRole) => new UserRoleLoggingView(userRole, false).toJSON()) : undefined, referrerId: this.self.referrerId, contributionLinkId: this.self.contributionLinkId, @@ -50,7 +53,7 @@ export class UserLoggingView extends AbstractLoggingView { : undefined, userContacts: this.self.userContacts ? this.self.userContacts.map((userContact) => - new UserContactLoggingView(userContact).toJSON(), + new UserContactLoggingView(userContact, false).toJSON(), ) : undefined, } diff --git a/database/src/logging/UserRoleLogging.view.ts b/database/src/logging/UserRoleLogging.view.ts index 52684d242..ebfa3aed8 100644 --- a/database/src/logging/UserRoleLogging.view.ts +++ b/database/src/logging/UserRoleLogging.view.ts @@ -3,14 +3,14 @@ import { AbstractLoggingView } from './AbstractLogging.view' import { UserLoggingView } from './UserLogging.view' export class UserRoleLoggingView extends AbstractLoggingView { - public constructor(private self: UserRole) { + public constructor(private self: UserRole, private showUser = true) { super() } public toJSON(): any { return { id: this.self.id, - user: this.self.user + user: this.showUser && this.self.user ? new UserLoggingView(this.self.user).toJSON() : { id: this.self.userId }, role: this.self.role, diff --git a/database/src/queries/events.ts b/database/src/queries/events.ts new file mode 100644 index 000000000..ff0967944 --- /dev/null +++ b/database/src/queries/events.ts @@ -0,0 +1,19 @@ +import { + ContributionLink as DbContributionLink, + Event as DbEvent, + User as DbUser +} from '../entity' + +export async function findModeratorCreatingContributionLink(contributionLink: DbContributionLink): Promise { + const event = await DbEvent.findOne( + { + where: { + involvedContributionLinkId: contributionLink.id, + // todo: move event types into db + type: 'ADMIN_CONTRIBUTION_LINK_CREATE' + }, + relations: { actingUser: true } + } + ) + return event?.actingUser +} \ No newline at end of file diff --git a/database/src/queries/index.ts b/database/src/queries/index.ts index 1fec568bf..54b5c6d4e 100644 --- a/database/src/queries/index.ts +++ b/database/src/queries/index.ts @@ -5,5 +5,6 @@ export * from './communities' export * from './pendingTransactions' export * from './transactions' export * from './transactionLinks' +export * from './events' export const LOG4JS_QUERIES_CATEGORY_NAME = `${LOG4JS_BASE_CATEGORY_NAME}.queries` diff --git a/database/src/queries/user.ts b/database/src/queries/user.ts index 2cb0eaaee..eb3f58d60 100644 --- a/database/src/queries/user.ts +++ b/database/src/queries/user.ts @@ -12,6 +12,13 @@ export async function aliasExists(alias: string): Promise { return user !== null } +export async function getUserById(id: number, withCommunity: boolean = false, withEmailContact: boolean = false): Promise { + return DbUser.findOneOrFail({ + where: { id }, + relations: { community: withCommunity, emailContact: withEmailContact }, + }) +} + /** * * @param identifier could be gradidoID, alias or email of user diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 93b3943c1..c7616863d 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -4,6 +4,7 @@ "": { "name": "dlt-connector", "dependencies": { + "async-exit-hook": "^2.0.1", "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js", }, "devDependencies": { @@ -11,6 +12,7 @@ "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", + "@types/async-exit-hook": "^2.0.2", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", "elysia": "1.3.8", @@ -247,6 +249,8 @@ "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + "@types/async-exit-hook": ["@types/async-exit-hook@2.0.2", "", {}, "sha512-RJbTNivnnn+JzNiQTtUgwo/1S6QUHwI5JfXCeUPsqZXB4LuvRwvHhbKFSS5jFDYpk8XoEAYVW2cumBOdGpXL2Q=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -301,6 +305,8 @@ "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="], + "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 0815437ef..92a994345 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -9,6 +9,7 @@ import { TopicInfoQuery, TopicMessageSubmitTransaction, TopicUpdateTransaction, + TransactionId, TransactionReceipt, TransactionResponse, Wallet, @@ -30,6 +31,9 @@ export class HieroClient { wallet: Wallet client: Client logger: Logger + // transaction counter for logging + transactionInternNr: number = 0 + pendingPromises: Promise[] = [] private constructor() { this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) @@ -53,12 +57,23 @@ export class HieroClient { return HieroClient.instance } + public async waitForPendingPromises() { + const startTime = new Date() + this.logger.info(`waiting for ${this.pendingPromises.length} pending promises`) + await Promise.all(this.pendingPromises) + const endTime = new Date() + this.logger.info(`all pending promises resolved, used time: ${endTime.getTime() - startTime.getTime()}ms`) + } + public async sendMessage( topicId: HieroId, transaction: GradidoTransaction, - ): Promise<{ receipt: TransactionReceipt; response: TransactionResponse }> { - let startTime = new Date() - this.logger.addContext('topicId', topicId.toString()) + ): Promise { + const startTime = new Date() + this.transactionInternNr++ + const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) + logger.addContext('trNr', this.transactionInternNr) + logger.addContext('topicId', topicId.toString()) const serializedTransaction = transaction.getSerializedTransaction() if (!serializedTransaction) { throw new Error('cannot serialize transaction') @@ -68,29 +83,34 @@ export class HieroClient { topicId, message: serializedTransaction.data(), }).freezeWithSigner(this.wallet) - let endTime = new Date() - this.logger.info(`prepare message, until freeze, cost: ${endTime.getTime() - startTime.getTime()}ms`) - startTime = new Date() - const signedHieroTransaction = await hieroTransaction.signWithSigner(this.wallet) - endTime = new Date() - this.logger.info(`sign message, cost: ${endTime.getTime() - startTime.getTime()}ms`) - startTime = new Date() - const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) - endTime = new Date() - this.logger.info(`send message, cost: ${endTime.getTime() - startTime.getTime()}ms`) - startTime = new Date() - const sendReceipt = await sendResponse.getReceiptWithSigner(this.wallet) - endTime = new Date() - this.logger.info(`get receipt, cost: ${endTime.getTime() - startTime.getTime()}ms`) - this.logger.info( - `message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`, + // sign and execute transaction needs some time, so let it run in background + const pendingPromiseIndex = this.pendingPromises.push( + hieroTransaction.signWithSigner(this.wallet).then(async (signedHieroTransaction) => { + const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) + logger.info(`message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`) + if (logger.isInfoEnabled()) { + // only for logging + sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { + logger.info( + `message send status: ${receipt.status.toString()}`, + ) + }) + // only for logging + sendResponse.getRecordWithSigner(this.wallet).then((record) => { + logger.info(`message sent, cost: ${record.transactionFee.toString()}`) + const localEndTime = new Date() + logger.info(`HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`) + }) + } + }).catch((e) => { + logger.error(e) + }).finally(() => { + this.pendingPromises.splice(pendingPromiseIndex, 1) + }) ) - startTime = new Date() - const record = await sendResponse.getRecordWithSigner(this.wallet) - endTime = new Date() - this.logger.info(`get record, cost: ${endTime.getTime() - startTime.getTime()}ms`) - this.logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - return { receipt: sendReceipt, response: sendResponse } + const endTime = new Date() + logger.info(`HieroClient.sendMessage used time: ${endTime.getTime() - startTime.getTime()}ms`) + return hieroTransaction.transactionId } public async getBalance(): Promise { diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index afd517069..835a1cef5 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -46,9 +46,36 @@ async function main() { // listen for rpc request from backend (graphql replaced with elysiaJS) new Elysia().use(appRoutes).listen(CONFIG.DLT_CONNECTOR_PORT, () => { logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) + setupGracefulShutdown(logger) }) } +function setupGracefulShutdown(logger: Logger) { + const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'] + signals.forEach(sig => { + process.on(sig, async () => { + logger.info(`[shutdown] Got ${sig}, cleaning up…`) + await gracefulShutdown(logger) + process.exit(0) + }) + }) + + if (process.platform === "win32") { + const rl = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, + }) + rl.on("SIGINT", () => { + process.emit("SIGINT" as any) + }) + } +} + +async function gracefulShutdown(logger: Logger) { + logger.info('graceful shutdown') + await HieroClient.getInstance().waitForPendingPromises() +} + function loadConfig(): Logger { // configure log4js // TODO: replace late by loader from config-schema @@ -113,3 +140,7 @@ main().catch((e) => { console.error(e) process.exit(1) }) +function exitHook(arg0: () => void) { + throw new Error('Function not implemented.') +} + diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 8fde79267..5061233be 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -50,10 +50,12 @@ export async function SendToHieroContext( topic: HieroId, ): Promise => { const client = HieroClient.getInstance() - const resultMessage = await client.sendMessage(topic, gradidoTransaction) - const transactionId = resultMessage.response.transactionId.toString() - logger.info('transmitted Gradido Transaction to Hiero', { transactionId }) - return transactionId + const transactionId = await client.sendMessage(topic, gradidoTransaction) + if (!transactionId) { + throw new Error('missing transaction id from hiero') + } + logger.info('transmitted Gradido Transaction to Hiero', { transactionId: transactionId.toString() }) + return transactionId.toString() } // choose correct role based on transaction type and input type From cf254c10812b66a7f75bd079de077f176eef9555 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 27 Sep 2025 16:10:33 +0200 Subject: [PATCH 035/226] update gradido node api --- dlt-connector/bun.lock | 6 ------ dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts | 8 ++++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index c7616863d..93b3943c1 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -4,7 +4,6 @@ "": { "name": "dlt-connector", "dependencies": { - "async-exit-hook": "^2.0.1", "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js", }, "devDependencies": { @@ -12,7 +11,6 @@ "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", - "@types/async-exit-hook": "^2.0.2", "@types/bun": "^1.2.17", "dotenv": "^10.0.0", "elysia": "1.3.8", @@ -249,8 +247,6 @@ "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], - "@types/async-exit-hook": ["@types/async-exit-hook@2.0.2", "", {}, "sha512-RJbTNivnnn+JzNiQTtUgwo/1S6QUHwI5JfXCeUPsqZXB4LuvRwvHhbKFSS5jFDYpk8XoEAYVW2cumBOdGpXL2Q=="], - "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -305,8 +301,6 @@ "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="], - "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], - "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index 5b58ad258..c7f9d2fb7 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -64,7 +64,7 @@ export class GradidoNodeClient { ...parse(transactionIdentifierSchema, transactionIdentifier), format: 'base64', } - const response = await this.rpcCall<{ transaction: string }>('gettransaction', parameter) + const response = await this.rpcCall<{ transaction: string }>('getTransaction', parameter) if (response.isSuccess()) { // this.logger.debug('result: ', response.result.transaction) return parse(confirmedTransactionSchema, response.result.transaction) @@ -90,7 +90,7 @@ export class GradidoNodeClient { format: 'base64', topic: hieroTopic, } - const response = await this.rpcCall<{ transaction: string }>('getlasttransaction', parameter) + const response = await this.rpcCall<{ transaction: string }>('getLastTransaction', parameter) if (response.isSuccess()) { return parse(confirmedTransactionSchema, response.result.transaction) } @@ -151,7 +151,7 @@ export class GradidoNodeClient { format: 'base64', } const response = await this.rpcCallResolved<{ transactions: string[] }>( - 'listtransactionsforaddress', + 'getTransactionsForAddress', parameter, ) return response.transactions.map((transactionBase64) => @@ -176,7 +176,7 @@ export class GradidoNodeClient { topic: hieroTopic, } const response = await this.rpcCallResolved<{ addressType: string }>( - 'getaddresstype', + 'getAddressType', parameter, ) return parse(addressTypeSchema, response.addressType) From d61ea0de3024db4ebea9130f2311e6b4453057d6 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 30 Sep 2025 08:29:38 +0200 Subject: [PATCH 036/226] update default env --- dlt-connector/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index ba8fe5557..ff40bd5d1 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -13,7 +13,7 @@ IOTA_HOME_COMMUNITY_SEED=aabbccddeeff00112233445566778899aabbccddeeff00112233445 DLT_CONNECTOR_PORT=6010 # Gradido Node Server URL -NODE_SERVER_URL=http://localhost:8340 +NODE_SERVER_URL=http://localhost:8340/api # Gradido Blockchain GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=21ffbbc616fe From 08735a229661ed8fcd8efda04cb6566aaeb11e6d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 1 Oct 2025 16:44:36 +0200 Subject: [PATCH 037/226] add inspector and gradido node routes to nginx --- .gitmodules | 3 ++ deployment/bare_metal/.env.dist | 3 +- .../sites-available/gradido.conf.ssl.template | 47 +++++++++++++++++++ deployment/bare_metal/start.sh | 19 ++++++++ inspector | 1 + 5 files changed, 72 insertions(+), 1 deletion(-) create mode 160000 inspector diff --git a/.gitmodules b/.gitmodules index 8b1378917..8bc8740e0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1 +1,4 @@ +[submodule "inspector"] + path = inspector + url = https://github.com/gradido/inspector.git diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 11f5e1d76..f9a111feb 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -86,8 +86,9 @@ FEDERATION_COMMUNITY_APIS=1_0 GDT_ACTIVE=false # DLT-Connector (still in develop) -DLT_CONNECTOR=false +DLT_CONNECTOR=true DLT_CONNECTOR_PORT=6010 +NODE_SERVER_URL=http://localhost:8340/api # used for combining a newsletter on klicktipp with this gradido community # if used, user will be subscribed on register and can unsubscribe in his account diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index 3bc911d39..fd54a27cc 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -101,6 +101,22 @@ server { error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn; } + # Gradido-Node + location /dlt { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:8340/api/; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.dlt.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.dlt.log warn; + } + # Backend webhooks location /hook { limit_req zone=backend burst=20 nodelay; @@ -196,6 +212,37 @@ server { access_log $GRADIDO_LOG_PATH/nginx-access.admin.log gradido_log; error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; } + + # Admin Frontend + location /inspector { + limit_req zone=frontend burst=30 nodelay; + limit_conn addr 20; + alias $PROJECT_ROOT/inspector/build/; + index index.html; + + # caching rules for assets + # static assets + location ~* \.(?:woff2?|ttf|otf|eot|jpg|jpeg|png|gif|svg|webp|ico)$ { + # keep assets for a week + add_header Cache-Control "public, max-age=604800"; + try_files $uri =404; + } + # hashed assets + location ~* \.(?:js|css|json)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + try_files $uri =404; + } + + try_files $uri $uri/ /index.html = 404; + + # don't cache index.html + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires 0; + + access_log $GRADIDO_LOG_PATH/nginx-access.inspector.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.inspector.log warn; + } # Federation $FEDERATION_NGINX_CONF diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 19cafc077..ca9f7c57a 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -287,6 +287,17 @@ bun install log_step 'build all modules' turbo build --env-mode=loose --concurrency=$(nproc) +# build inspector and dlt-connector +log_step 'build inspector' +cd $PROJECT_ROOT/inspector +bun install +bun run build + +log_step 'build dlt-connector' +cd $PROJECT_ROOT/dlt-connector +bun install +bun run build + # database log_step 'Updating database' if [ "$DEPLOY_SEED_DATA" = "true" ]; then @@ -306,6 +317,14 @@ pm2 start --name gradido-backend \ -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log \ --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +if [ "$DLT_CONNECTOR" = true ] ; then + pm2 start --name dlt-connector \ + "env TZ=UTC NODE_ENV=production bun ./build/index.js" \ + --cwd $PROJECT_ROOT/dlt-connector \ + -l $GRADIDO_LOG_PATH/pm2.dlt-connector.$TODAY.log \ + --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +fi + pm2 save if [ ! -z $FEDERATION_DHT_TOPIC ]; then pm2 start --name gradido-dht-node \ diff --git a/inspector b/inspector new file mode 160000 index 000000000..ab1fcc035 --- /dev/null +++ b/inspector @@ -0,0 +1 @@ +Subproject commit ab1fcc03546a1e98e4f236243d6cef1ae4a566d6 From 3606f9189e9b73ff4fc8079b33b6f07c1f0d6c3b Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 7 Oct 2025 14:39:22 +0200 Subject: [PATCH 038/226] some fixes --- backend/src/apis/dltConnector/index.ts | 57 +- .../src/graphql/resolver/UserResolver.test.ts | 1 + .../sendTransactionsToDltConnector.test.ts | 799 ------------------ backend/src/index.ts | 1 - 4 files changed, 21 insertions(+), 837 deletions(-) delete mode 100644 backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index 671c88297..275a3d9d0 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -44,6 +44,20 @@ async function checkDltConnectorResult(dltTransaction: DbDltTransaction, clientR return dltTransaction } +async function executeDltTransaction(draft: TransactionDraft | null, typeId: DltTransactionType, persist = true): Promise { + if (draft && dltConnectorClient) { + const clientResponse = dltConnectorClient.sendTransaction(draft) + let dltTransaction = new DbDltTransaction() + dltTransaction.typeId = typeId + dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) + if (persist) { + return await dltTransaction.save() + } + return dltTransaction + } + return Promise.resolve(null) +} + /** * send register address transaction via dlt-connector to hiero * and update dltTransactionId of transaction in db with hiero transaction id @@ -55,14 +69,11 @@ export async function registerAddressTransaction(user: DbUser, community: DbComm } // return null if some data where missing and log error const draft = TransactionDraft.createRegisterAddress(user, community) - if (draft && dltConnectorClient) { - const clientResponse = dltConnectorClient.sendTransaction(draft) - let dltTransaction = new DbDltTransaction() - dltTransaction.typeId = DltTransactionType.REGISTER_ADDRESS + const dltTransaction = await executeDltTransaction(draft, DltTransactionType.REGISTER_ADDRESS, false) + if (dltTransaction) { if (user.id) { dltTransaction.userId = user.id } - dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) return await dltTransaction.save() } return null @@ -79,14 +90,7 @@ export async function contributionTransaction( return null } const draft = TransactionDraft.createContribution(contribution, createdAt, signingUser, homeCommunity) - if (draft && dltConnectorClient) { - const clientResponse = dltConnectorClient.sendTransaction(draft) - let dltTransaction = new DbDltTransaction() - dltTransaction.typeId = DltTransactionType.CREATION - dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) - return await dltTransaction.save() - } - return null + return await executeDltTransaction(draft, DltTransactionType.CREATION) } export async function transferTransaction( @@ -106,14 +110,7 @@ export async function transferTransaction( logger.info(`sender user: ${new UserLoggingView(senderUser)}`) logger.info(`recipient user: ${new UserLoggingView(recipientUser)}`) const draft = TransactionDraft.createTransfer(senderUser, recipientUser, amount, memo, createdAt) - if (draft && dltConnectorClient) { - const clientResponse = dltConnectorClient.sendTransaction(draft) - let dltTransaction = new DbDltTransaction() - dltTransaction.typeId = DltTransactionType.TRANSFER - dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) - return await dltTransaction.save() - } - return null + return await executeDltTransaction(draft, DltTransactionType.TRANSFER) } export async function deferredTransferTransaction(senderUser: DbUser, transactionLink: DbTransactionLink) @@ -123,14 +120,7 @@ export async function deferredTransferTransaction(senderUser: DbUser, transactio senderUser.community = await getCommunityByUuid(senderUser.communityUuid) } const draft = TransactionDraft.createDeferredTransfer(senderUser, transactionLink) - if (draft && dltConnectorClient) { - const clientResponse = dltConnectorClient.sendTransaction(draft) - let dltTransaction = new DbDltTransaction() - dltTransaction.typeId = DltTransactionType.DEFERRED_TRANSFER - dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) - return await dltTransaction.save() - } - return null + return await executeDltTransaction(draft, DltTransactionType.DEFERRED_TRANSFER) } export async function redeemDeferredTransferTransaction(transactionLink: DbTransactionLink, amount: string, createdAt: Date, recipientUser: DbUser) @@ -151,14 +141,7 @@ export async function redeemDeferredTransferTransaction(transactionLink: DbTrans logger.debug(`sender: ${new UserLoggingView(transactionLink.user)}`) logger.debug(`recipient: ${new UserLoggingView(recipientUser)}`) const draft = TransactionDraft.redeemDeferredTransfer(transactionLink, amount, createdAt, recipientUser) - if (draft && dltConnectorClient) { - const clientResponse = dltConnectorClient.sendTransaction(draft) - let dltTransaction = new DbDltTransaction() - dltTransaction.typeId = DltTransactionType.REDEEM_DEFERRED_TRANSFER - dltTransaction = await checkDltConnectorResult(dltTransaction, clientResponse) - return await dltTransaction.save() - } - return null + return await executeDltTransaction(draft, DltTransactionType.REDEEM_DEFERRED_TRANSFER) } diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 64817bd3e..cee570c94 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -117,6 +117,7 @@ beforeAll(async () => { query = testEnv.query con = testEnv.con CONFIG.HUMHUB_ACTIVE = false + CONFIG.DLT_CONNECTOR = false await cleanDB() }) diff --git a/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts b/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts deleted file mode 100644 index 769730544..000000000 --- a/backend/src/graphql/resolver/util/sendTransactionsToDltConnector.test.ts +++ /dev/null @@ -1,799 +0,0 @@ -import { ApolloServerTestClient } from 'apollo-server-testing' -import { Community, DltTransaction, Transaction } from 'database' -import { Decimal } from 'decimal.js-light' -// import { GraphQLClient } from 'graphql-request' -// import { Response } from 'graphql-request/dist/types' -import { GraphQLClient } from 'graphql-request' -import { Response } from 'graphql-request/dist/types' -import { DataSource } from 'typeorm' -import { v4 as uuidv4 } from 'uuid' - -import { cleanDB, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' - -import { CONFIG } from '@/config' -import { TransactionTypeId } from 'core' -import { creations } from '@/seeds/creation' -import { creationFactory } from '@/seeds/factory/creation' -import { userFactory } from '@/seeds/factory/user' -import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { bobBaumeister } from '@/seeds/users/bob-baumeister' -import { peterLustig } from '@/seeds/users/peter-lustig' -import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' -import { getLogger } from 'config-schema/test/testSetup' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' - -import { sendTransactionsToDltConnector } from './sendTransactionsToDltConnector' - -jest.mock('@/password/EncryptorUtils') - -const logger = getLogger( - `${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.sendTransactionsToDltConnector`, -) - -/* -// Mock the GraphQLClient -jest.mock('graphql-request', () => { - const originalModule = jest.requireActual('graphql-request') - - let testCursor = 0 - - return { - __esModule: true, - ...originalModule, - GraphQLClient: jest.fn().mockImplementation((url: string) => { - if (url === 'invalid') { - throw new Error('invalid url') - } - return { - // why not using mockResolvedValueOnce or mockReturnValueOnce? - // I have tried, but it didn't work and return every time the first value - request: jest.fn().mockImplementation(() => { - testCursor++ - if (testCursor === 4) { - return Promise.resolve( - // invalid, is 33 Bytes long as binary - { - transmitTransaction: { - dltTransactionIdHex: - '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516212A', - }, - }, - ) - } else if (testCursor === 5) { - throw Error('Connection error') - } else { - return Promise.resolve( - // valid, is 32 Bytes long as binary - { - transmitTransaction: { - dltTransactionIdHex: - '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc51621', - }, - }, - ) - } - }), - } - }), - } -}) -let mutate: ApolloServerTestClient['mutate'], - query: ApolloServerTestClient['query'], - con: Connection -let testEnv: { - mutate: ApolloServerTestClient['mutate'] - query: ApolloServerTestClient['query'] - con: Connection -} -*/ - -async function createHomeCommunity(): Promise { - const homeCommunity = Community.create() - homeCommunity.foreign = false - homeCommunity.communityUuid = uuidv4() - homeCommunity.url = 'localhost' - homeCommunity.publicKey = Buffer.from('0x6e6a6c6d6feffe', 'hex') - await Community.save(homeCommunity) - return homeCommunity -} - -async function createTxCREATION1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(100) - tx.balanceDate = new Date('01.01.2023 00:00:00') - tx.memo = 'txCREATION1' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION1.userGradidoID' - tx.userId = 1 - tx.userName = 'txCREATION 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('01.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('01.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxCREATION2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(200) - tx.balanceDate = new Date('02.01.2023 00:00:00') - tx.memo = 'txCREATION2' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION2.userGradidoID' - tx.userId = 2 - tx.userName = 'txCREATION 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('02.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('02.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxCREATION3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(1000) - tx.balance = new Decimal(300) - tx.balanceDate = new Date('03.01.2023 00:00:00') - tx.memo = 'txCREATION3' - tx.typeId = TransactionTypeId.CREATION - tx.userGradidoID = 'txCREATION3.userGradidoID' - tx.userId = 3 - tx.userName = 'txCREATION 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('03.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('03.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxSend1ToReceive2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(100) - tx.balance = new Decimal(1000) - tx.balanceDate = new Date('11.01.2023 00:00:00') - tx.memo = 'txSEND1 to txRECEIVE2' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND1.userGradidoID' - tx.userId = 1 - tx.userName = 'txSEND 1' - tx.linkedUserGradidoID = 'txRECEIVE2.linkedUserGradidoID' - tx.linkedUserId = 2 - tx.linkedUserName = 'txRECEIVE 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('11.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('11.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive2FromSend1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(100) - tx.balance = new Decimal(1300) - tx.balanceDate = new Date('11.01.2023 00:00:00') - tx.memo = 'txSEND1 to txRECEIVE2' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE2.linkedUserGradidoID' - tx.userId = 2 - tx.userName = 'txRECEIVE 2' - tx.linkedUserGradidoID = 'txSEND1.userGradidoID' - tx.linkedUserId = 1 - tx.linkedUserName = 'txSEND 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('11.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('11.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -/* -async function createTxSend2ToReceive3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(200) - tx.balance = new Decimal(1100) - tx.balanceDate = new Date('23.01.2023 00:00:00') - tx.memo = 'txSEND2 to txRECEIVE3' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND2.userGradidoID' - tx.userId = 2 - tx.userName = 'txSEND 2' - tx.linkedUserGradidoID = 'txRECEIVE3.linkedUserGradidoID' - tx.linkedUserId = 3 - tx.linkedUserName = 'txRECEIVE 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('23.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a2' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('23.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive3FromSend2(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(200) - tx.balance = new Decimal(1500) - tx.balanceDate = new Date('23.01.2023 00:00:00') - tx.memo = 'txSEND2 to txRECEIVE3' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE3.linkedUserGradidoID' - tx.userId = 3 - tx.userName = 'txRECEIVE 3' - tx.linkedUserGradidoID = 'txSEND2.userGradidoID' - tx.linkedUserId = 2 - tx.linkedUserName = 'txSEND 2' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('23.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('23.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxSend3ToReceive1(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(300) - tx.balance = new Decimal(1200) - tx.balanceDate = new Date('31.01.2023 00:00:00') - tx.memo = 'txSEND3 to txRECEIVE1' - tx.typeId = TransactionTypeId.SEND - tx.userGradidoID = 'txSEND3.userGradidoID' - tx.userId = 3 - tx.userName = 'txSEND 3' - tx.linkedUserGradidoID = 'txRECEIVE1.linkedUserGradidoID' - tx.linkedUserId = 1 - tx.linkedUserName = 'txRECEIVE 1' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('31.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516a3' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('31.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} - -async function createTxReceive1FromSend3(verified: boolean): Promise { - let tx = Transaction.create() - tx.amount = new Decimal(300) - tx.balance = new Decimal(1300) - tx.balanceDate = new Date('31.01.2023 00:00:00') - tx.memo = 'txSEND3 to txRECEIVE1' - tx.typeId = TransactionTypeId.RECEIVE - tx.userGradidoID = 'txRECEIVE1.linkedUserGradidoID' - tx.userId = 1 - tx.userName = 'txRECEIVE 1' - tx.linkedUserGradidoID = 'txSEND3.userGradidoID' - tx.linkedUserId = 3 - tx.linkedUserName = 'txSEND 3' - tx = await Transaction.save(tx) - - if (verified) { - const dlttx = DltTransaction.create() - dlttx.createdAt = new Date('31.01.2023 00:00:10') - dlttx.messageId = '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516b1' - dlttx.transactionId = tx.id - dlttx.verified = true - dlttx.verifiedAt = new Date('31.01.2023 00:01:10') - await DltTransaction.save(dlttx) - } - return tx -} -*/ - -let con: DataSource -let testEnv: { - mutate: ApolloServerTestClient['mutate'] - query: ApolloServerTestClient['query'] - con: DataSource -} - -beforeAll(async () => { - testEnv = await testEnvironment(logger, localization) - con = testEnv.con - await cleanDB() -}) - -afterAll(async () => { - await cleanDB() - await con.destroy() -}) - -describe('create and send Transactions to DltConnector', () => { - let txCREATION1: Transaction - let txCREATION2: Transaction - let txCREATION3: Transaction - let txSEND1to2: Transaction - let txRECEIVE2From1: Transaction - // let txSEND2To3: Transaction - // let txRECEIVE3From2: Transaction - // let txSEND3To1: Transaction - // let txRECEIVE1From3: Transaction - - beforeEach(() => { - jest.clearAllMocks() - }) - - afterEach(async () => { - await cleanDB() - }) - - describe('with 3 creations but inactive dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - txCREATION1 = await createTxCREATION1(false) - txCREATION2 = await createTxCREATION2(false) - txCREATION3 = await createTxCREATION3(false) - await createHomeCommunity() - - CONFIG.DLT_CONNECTOR = false - await sendTransactionsToDltConnector() - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[0].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[1].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[2].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - - expect(logger.info).nthCalledWith(2, 'sending to DltConnector currently not configured...') - }) - }) - - describe('with 3 creations and active dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - await userFactory(testEnv, raeuberHotzenplotz) - await userFactory(testEnv, bobBaumeister) - let count = 0 - for (const creation of creations) { - await creationFactory(testEnv, creation) - count++ - // we need only 3 for testing - if (count >= 3) { - break - } - } - await createHomeCommunity() - - CONFIG.DLT_CONNECTOR = true - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - return { - data: { - sendTransaction: { succeed: true }, - }, - } as Response - }) - - await sendTransactionsToDltConnector() - - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[0].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[1].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transactions[2].id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - }) - }) - - describe('with 3 verified creations, 1 sendCoins and active dlt-connector', () => { - it('found 3 dlt-transactions', async () => { - txCREATION1 = await createTxCREATION1(true) - txCREATION2 = await createTxCREATION2(true) - txCREATION3 = await createTxCREATION3(true) - await createHomeCommunity() - - txSEND1to2 = await createTxSend1ToReceive2(false) - txRECEIVE2From1 = await createTxReceive2FromSend1(false) - - /* - txSEND2To3 = await createTxSend2ToReceive3() - txRECEIVE3From2 = await createTxReceive3FromSend2() - txSEND3To1 = await createTxSend3ToReceive1() - txRECEIVE1From3 = await createTxReceive1FromSend3() - */ - - CONFIG.DLT_CONNECTOR = true - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - return { - data: { - sendTransaction: { succeed: true }, - }, - } as Response - }) - - await sendTransactionsToDltConnector() - - expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...') - - // Find the previous created transactions of sendCoin mutation - /* - const transactions = await Transaction.find({ - // where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - */ - - const dltTransactions = await DltTransaction.find({ - // where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - order: { createdAt: 'ASC', id: 'ASC' }, - }) - - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION1.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c1', - verified: true, - createdAt: new Date('01.01.2023 00:00:10'), - verifiedAt: new Date('01.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION2.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c2', - verified: true, - createdAt: new Date('02.01.2023 00:00:10'), - verifiedAt: new Date('02.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txCREATION3.id, - messageId: '723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516c3', - verified: true, - createdAt: new Date('03.01.2023 00:00:10'), - verifiedAt: new Date('03.01.2023 00:01:10'), - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txSEND1to2.id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: txRECEIVE2From1.id, - messageId: 'sended', - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - }) - /* - describe('with one Community of api 1_0 and not matching pubKey', () => { - beforeEach(async () => { - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: 'somePubKey', - }, - }, - } as Response - }) - const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables1) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - - jest.clearAllMocks() - // await validateCommunities() - }) - - it('logs one community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs not matching publicKeys', () => { - expect(logger.warn).toBeCalledWith( - 'Federation: received not matching publicKey:', - 'somePubKey', - expect.stringMatching('11111111111111111111111111111111'), - ) - }) - }) - describe('with one Community of api 1_0 and matching pubKey', () => { - beforeEach(async () => { - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: '11111111111111111111111111111111', - }, - }, - } as Response - }) - const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables1) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - - it('logs one community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs community pubKey verified', () => { - expect(logger.info).toHaveBeenNthCalledWith( - 3, - 'Federation: verified community with', - 'http//localhost:5001/api/', - ) - }) - }) - describe('with two Communities of api 1_0 and 1_1', () => { - beforeEach(async () => { - jest.clearAllMocks() - - jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { - - return { - data: { - getPublicKey: { - publicKey: '11111111111111111111111111111111', - }, - }, - } as Response - }) - const variables2 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '1_1', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables2) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - it('logs two communities found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 2 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs requestGetPublicKey for community api 1_1 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_1/', - ) - }) - }) - describe('with three Communities of api 1_0, 1_1 and 2_0', () => { - let dbCom: DbFederatedCommunity - beforeEach(async () => { - const variables3 = { - publicKey: Buffer.from('11111111111111111111111111111111'), - apiVersion: '2_0', - endPoint: 'http//localhost:5001/api/', - lastAnnouncedAt: new Date(), - } - await DbFederatedCommunity.createQueryBuilder() - .insert() - .into(DbFederatedCommunity) - .values(variables3) - .orUpdate({ - - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - dbCom = await DbFederatedCommunity.findOneOrFail({ - where: { publicKey: variables3.publicKey, apiVersion: variables3.apiVersion }, - }) - await DbFederatedCommunity.update({}, { verifiedAt: null }) - jest.clearAllMocks() - // await validateCommunities() - }) - it('logs three community found', () => { - expect(logger.debug).toBeCalledWith(`Federation: found 3 dbCommunities`) - }) - it('logs requestGetPublicKey for community api 1_0 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_0/', - ) - }) - it('logs requestGetPublicKey for community api 1_1 ', () => { - expect(logger.info).toBeCalledWith( - 'Federation: getPublicKey from endpoint', - 'http//localhost:5001/api/1_1/', - ) - }) - it('logs unsupported api for community with api 2_0 ', () => { - expect(logger.warn).toBeCalledWith( - 'Federation: dbCom with unsupported apiVersion', - dbCom.endPoint, - '2_0', - ) - }) - }) - */ - }) -}) diff --git a/backend/src/index.ts b/backend/src/index.ts index 8a46cbb35..d7e883933 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,6 @@ import 'reflect-metadata' import 'source-map-support/register' import { getLogger } from 'log4js' -import { sendTransactionsToDltConnector } from './apis/dltConnector/sendTransactionsToDltConnector' import { CONFIG } from './config' import { startValidateCommunities } from './federation/validateCommunities' import { createServer } from './server/createServer' From 9ede9c0e5bc9dabaf76c453d8e478608c30dcd7f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 7 Oct 2025 15:28:06 +0200 Subject: [PATCH 039/226] fix backend user resolver test --- backend/package.json | 8 +- backend/src/apis/dltConnector/index.ts | 16 + .../src/graphql/resolver/UserResolver.test.ts | 8 +- backend/src/seeds/factory/user.ts | 1 - bun.lock | 2724 +++++++++++++---- 5 files changed, 2203 insertions(+), 554 deletions(-) diff --git a/backend/package.json b/backend/package.json index 659ac59dc..2378eed04 100644 --- a/backend/package.json +++ b/backend/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "cross-env": "^7.0.3", - "email-templates": "^10.0.1", + "email-templates": "10.0.1", "sodium-native": "^3.4.1" }, "devDependencies": { @@ -41,14 +41,14 @@ "@swc/cli": "^0.7.3", "@swc/core": "^1.11.24", "@swc/helpers": "^0.5.17", - "@types/email-templates": "^10.0.4", + "@types/email-templates": "10.0.1", "@types/express": "^4.17.21", "@types/faker": "^5.5.9", "@types/i18n": "^0.13.4", "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "^6.4.4", + "@types/nodemailer": "6.4.17", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -82,7 +82,7 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "^6.6.5", + "nodemailer": "6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index 275a3d9d0..bce319674 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -15,6 +15,7 @@ import { UserLoggingView, } from 'database' import { TransactionDraft } from './model/TransactionDraft' +import { CONFIG } from '@/config' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector`) // will be undefined if dlt connect is disabled @@ -63,6 +64,9 @@ async function executeDltTransaction(draft: TransactionDraft | null, typeId: Dlt * and update dltTransactionId of transaction in db with hiero transaction id */ export async function registerAddressTransaction(user: DbUser, community: DbCommunity): Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve(null) + } if (!user.id) { logger.error(`missing id for user: ${user.gradidoID}, please call registerAddressTransaction after user.save()`) return null @@ -84,6 +88,9 @@ export async function contributionTransaction( signingUser: DbUser, createdAt: Date, ): Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve(null) + } const homeCommunity = await getHomeCommunity() if (!homeCommunity) { logger.error('home community not found') @@ -100,6 +107,9 @@ export async function transferTransaction( memo: string, createdAt: Date ): Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve(null) + } // load community if not already loaded, maybe they are remote communities if (!senderUser.community) { senderUser.community = await getCommunityByUuid(senderUser.communityUuid) @@ -115,6 +125,9 @@ export async function transferTransaction( export async function deferredTransferTransaction(senderUser: DbUser, transactionLink: DbTransactionLink) : Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve(null) + } // load community if not already loaded if (!senderUser.community) { senderUser.community = await getCommunityByUuid(senderUser.communityUuid) @@ -125,6 +138,9 @@ export async function deferredTransferTransaction(senderUser: DbUser, transactio export async function redeemDeferredTransferTransaction(transactionLink: DbTransactionLink, amount: string, createdAt: Date, recipientUser: DbUser) : Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve(null) + } // load user and communities if not already loaded if (!transactionLink.user) { logger.debug('load sender user') diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index cee570c94..35142e890 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -79,11 +79,9 @@ jest.mock('@/emails/sendEmailVariants', () => { return { __esModule: true, ...originalModule, - sendAccountActivationEmail: jest.fn((a) => originalModule.sendAccountActivationEmail(a)), - sendAccountMultiRegistrationEmail: jest.fn((a) => - originalModule.sendAccountMultiRegistrationEmail(a), - ), - sendResetPasswordEmail: jest.fn((a) => originalModule.sendResetPasswordEmail(a)), + sendAccountActivationEmail: jest.fn(), + sendAccountMultiRegistrationEmail: jest.fn(), + sendResetPasswordEmail: jest.fn(), } }) diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 3cae22f71..5da84c3b2 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -13,7 +13,6 @@ export const userFactory = async ( user: UserInterface, ): Promise => { const { mutate } = client - const homeCom = await writeHomeCommunityEntry() // console.log('call createUser with', JSON.stringify(user, null, 2)) const response = await mutate({ mutation: createUser, variables: user }) diff --git a/bun.lock b/bun.lock index 0a55639b6..88deb2864 100644 --- a/bun.lock +++ b/bun.lock @@ -88,7 +88,7 @@ "version": "2.6.1", "dependencies": { "cross-env": "^7.0.3", - "email-templates": "^10.0.1", + "email-templates": "10.0.1", "sodium-native": "^3.4.1", }, "devDependencies": { @@ -97,14 +97,14 @@ "@swc/cli": "^0.7.3", "@swc/core": "^1.11.24", "@swc/helpers": "^0.5.17", - "@types/email-templates": "^10.0.4", + "@types/email-templates": "10.0.1", "@types/express": "^4.17.21", "@types/faker": "^5.5.9", "@types/i18n": "^0.13.4", "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "^6.4.4", + "@types/nodemailer": "6.4.17", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -138,7 +138,7 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "^6.6.5", + "nodemailer": "6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", @@ -458,7 +458,7 @@ "@antfu/utils": ["@antfu/utils@0.7.10", "", {}, "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww=="], - "@apollo/client": ["@apollo/client@3.13.8", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", "@wry/equality": "^0.5.6", "@wry/trie": "^0.5.0", "graphql-tag": "^2.12.6", "hoist-non-react-statics": "^3.3.2", "optimism": "^0.18.0", "prop-types": "^15.7.2", "rehackt": "^0.1.0", "symbol-observable": "^4.0.0", "ts-invariant": "^0.10.3", "tslib": "^2.3.0", "zen-observable-ts": "^1.2.5" }, "peerDependencies": { "graphql": "^15.0.0 || ^16.0.0", "graphql-ws": "^5.5.5 || ^6.0.3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" }, "optionalPeers": ["graphql-ws", "react", "react-dom", "subscriptions-transport-ws"] }, "sha512-YM9lQpm0VfVco4DSyKooHS/fDTiKQcCHfxr7i3iL6a0kP/jNO5+4NFK6vtRDxaYisd5BrwOZHLJpPBnvRVpKPg=="], + "@apollo/client": ["@apollo/client@3.14.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", "@wry/equality": "^0.5.6", "@wry/trie": "^0.5.0", "graphql-tag": "^2.12.6", "hoist-non-react-statics": "^3.3.2", "optimism": "^0.18.0", "prop-types": "^15.7.2", "rehackt": "^0.1.0", "symbol-observable": "^4.0.0", "ts-invariant": "^0.10.3", "tslib": "^2.3.0", "zen-observable-ts": "^1.2.5" }, "peerDependencies": { "graphql": "^15.0.0 || ^16.0.0", "graphql-ws": "^5.5.5 || ^6.0.3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" }, "optionalPeers": ["graphql-ws", "react", "react-dom", "subscriptions-transport-ws"] }, "sha512-0YQKKRIxiMlIou+SekQqdCo0ZTHxOcES+K8vKB53cIDpwABNR0P0yRzPgsbgcj3zRJniD93S/ontsnZsCLZrxQ=="], "@apollo/protobufjs": ["@apollo/protobufjs@1.2.2", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/long": "^4.0.0", "@types/node": "^10.1.0", "long": "^4.0.0" }, "bin": { "apollo-pbjs": "bin/pbjs", "apollo-pbts": "bin/pbts" } }, "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ=="], @@ -468,21 +468,23 @@ "@apollographql/graphql-upload-8-fork": ["@apollographql/graphql-upload-8-fork@8.1.4", "", { "dependencies": { "@types/express": "*", "@types/fs-capacitor": "^2.0.0", "@types/koa": "*", "busboy": "^0.3.1", "fs-capacitor": "^2.0.4", "http-errors": "^1.7.3", "object-path": "^0.11.4" }, "peerDependencies": { "graphql": "0.13.1 - 15" } }, "sha512-lHAj/PUegYu02zza9Pg0bQQYH5I0ah1nyIzu2YIqOv41P0vu3GCBISAmQCfFHThK7N3dy7dLFPhoKcXlXRLPoQ=="], - "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.1.7", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-Ok5fYhtwdyJQmU1PpEv6Si7Y+A4cYb8yNM9oiIJC9TzXPMuN9fvdonKJqcnz9TbFqV6bQ8z0giRq0iaOpGZV2g=="], + "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.27.1", "", {}, "sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A=="], + "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="], - "@babel/core": ["@babel/core@7.27.1", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-module-transforms": "^7.27.1", "@babel/helpers": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ=="], + "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], - "@babel/generator": ["@babel/generator@7.27.1", "", { "dependencies": { "@babel/parser": "^7.27.1", "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w=="], + "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.1", "", { "dependencies": { "@babel/compat-data": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g=="], + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g=="], + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], @@ -492,9 +494,9 @@ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helpers": ["@babel/helpers@7.27.1", "", { "dependencies": { "@babel/template": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ=="], + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" }, "bin": "./bin/babel-parser.js" }, "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ=="], + "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="], "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], @@ -510,6 +512,8 @@ "@babel/plugin-syntax-json-strings": ["@babel/plugin-syntax-json-strings@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA=="], + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], + "@babel/plugin-syntax-logical-assignment-operators": ["@babel/plugin-syntax-logical-assignment-operators@7.10.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig=="], "@babel/plugin-syntax-nullish-coalescing-operator": ["@babel/plugin-syntax-nullish-coalescing-operator@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="], @@ -528,111 +532,121 @@ "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], - "@babel/runtime": ["@babel/runtime@7.27.1", "", {}, "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], - "@babel/runtime-corejs3": ["@babel/runtime-corejs3@7.27.1", "", { "dependencies": { "core-js-pure": "^3.30.2" } }, "sha512-909rVuj3phpjW6y0MCXAZ5iNeORePa6ldJvp2baWGcTjwqbBDDz6xoS5JHJ7lS88NlwLYj07ImL/8IUMtDZzTA=="], + "@babel/runtime-corejs3": ["@babel/runtime-corejs3@7.28.4", "", { "dependencies": { "core-js-pure": "^3.43.0" } }, "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ=="], - "@babel/template": ["@babel/template@7.27.1", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg=="], + "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.27.1", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.1", "@babel/parser": "^7.27.1", "@babel/template": "^7.27.1", "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg=="], + "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], - "@babel/types": ["@babel/types@7.27.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q=="], + "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], - "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + + "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], + + "@cacheable/memoize": ["@cacheable/memoize@2.0.3", "", { "dependencies": { "@cacheable/utils": "^2.0.3" } }, "sha512-hl9wfQgpiydhQEIv7fkjEzTGE+tcosCXLKFDO707wYJ/78FVOlowb36djex5GdbSyeHnG62pomYLMuV/OT8Pbw=="], + + "@cacheable/memory": ["@cacheable/memory@2.0.3", "", { "dependencies": { "@cacheable/memoize": "^2.0.3", "@cacheable/utils": "^2.0.3", "@keyv/bigmap": "^1.0.2", "hookified": "^1.12.1", "keyv": "^5.5.3" } }, "sha512-R3UKy/CKOyb1LZG/VRCTMcpiMDyLH7SH3JrraRdK6kf3GweWCOU3sgvE13W3TiDRbxnDKylzKJvhUAvWl9LQOA=="], + + "@cacheable/utils": ["@cacheable/utils@2.1.0", "", { "dependencies": { "keyv": "^5.5.3" } }, "sha512-ZdxfOiaarMqMj+H7qwlt5EBKWaeGihSYVHdQv5lUsbn8MJJOTW82OIwirQ39U5tMZkNvy3bQE+ryzC+xTAb9/g=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], - "@csstools/color-helpers": ["@csstools/color-helpers@5.0.2", "", {}, "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA=="], + "@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="], - "@csstools/css-calc": ["@csstools/css-calc@2.1.3", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" } }, "sha512-XBG3talrhid44BY1x3MHzUx/aTG8+x/Zi57M4aTKK9RFB4aLlF3TTSzfzn8nWVHWL3FgAXAxmupmDd6VWww+pw=="], + "@csstools/css-calc": ["@csstools/css-calc@2.1.4", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ=="], - "@csstools/css-color-parser": ["@csstools/css-color-parser@3.0.9", "", { "dependencies": { "@csstools/color-helpers": "^5.0.2", "@csstools/css-calc": "^2.1.3" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" } }, "sha512-wILs5Zk7BU86UArYBJTPy/FMPPKVKHMj1ycCEyf3VUptol0JNRLFU/BZsJ4aiIHJEbSLiizzRrw8Pc1uAEDrXw=="], + "@csstools/css-color-parser": ["@csstools/css-color-parser@3.1.0", "", { "dependencies": { "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA=="], - "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.4", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.3" } }, "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A=="], + "@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="], - "@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.3", "", {}, "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw=="], + "@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="], - "@csstools/media-query-list-parser": ["@csstools/media-query-list-parser@4.0.2", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" } }, "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A=="], + "@csstools/media-query-list-parser": ["@csstools/media-query-list-parser@4.0.3", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ=="], "@csstools/selector-specificity": ["@csstools/selector-specificity@5.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw=="], - "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.1.0", "", {}, "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg=="], + "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="], - "@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], + "@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" } }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="], - "@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], @@ -640,7 +654,7 @@ "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], - "@googlemaps/js-api-loader": ["@googlemaps/js-api-loader@1.16.8", "", {}, "sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ=="], + "@googlemaps/js-api-loader": ["@googlemaps/js-api-loader@1.16.10", "", {}, "sha512-c2erv2k7P2ilYzMmtYcMgAR21AULosQuUHJbStnrvRk2dG93k5cqptDrh9A8p+ZNlyhiqEOgHW7N9PAizdUM7Q=="], "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], @@ -666,19 +680,19 @@ "@hyperswarm/secret-stream": ["@hyperswarm/secret-stream@6.8.1", "", { "dependencies": { "b4a": "^1.1.0", "hypercore-crypto": "^3.3.1", "noise-curve-ed": "^2.0.1", "noise-handshake": "^4.0.0", "sodium-secretstream": "^1.1.0", "sodium-universal": "^5.0.0", "streamx": "^2.14.0", "timeout-refresh": "^2.0.0", "unslab": "^1.3.0" } }, "sha512-F3fr8CKB6za9Ac7ifjgAe07qnnesl5kS0MtLsyKxA1Og8E+FZykdwLpgoLjnEa7G6E1L56lASLr42E4kd20sog=="], - "@iconify-json/arcticons": ["@iconify-json/arcticons@1.2.24", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-l5mQELXr9Sv87DPmEcUJ3Ub1qNbRKpr4ax+0LoBbYmHU+osTdJ3FNgTH04/VKMKp2+95MNbA5Tt6gwgPkj5FNQ=="], + "@iconify-json/arcticons": ["@iconify-json/arcticons@1.2.38", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-AnPvt17WFSGkakgWHRobIrRi1SEPmpzRAoOn6SokwoaItBzjUcgvRNW/GDuh/PWZwI5T4+VRJaBmB4Owa1Cktw=="], - "@iconify-json/bi": ["@iconify-json/bi@1.2.3", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-pDNU9mIKDfvVEGxWsExiuVEqyhyJ5q5bOwBTgtM7I2hGk9ACQaiogMaA6lBRJ82sJPj+Uv21Oi+ujThGnMW2jA=="], + "@iconify-json/bi": ["@iconify-json/bi@1.2.6", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-fWfLr1/+DJDe8+rIUXxMwvmWBZFlxRtM59sYnrezJ2xX87QKyXVw3QuforJ4kF2Orrz85J+JTRG6305vaJ7flA=="], - "@iconify-json/fa": ["@iconify-json/fa@1.2.1", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-aY2+tQNWq5ch+ShtAz3KKbNrFfwf4BPrXvyN7S4/lcf6Wms+kIxsd7C7KortzHZhoBnbhVN+qo+YUWLW7rLs9Q=="], + "@iconify-json/fa": ["@iconify-json/fa@1.2.2", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-Rw0L97uO3W0Gy2rq4cM/TH3QjzuPuRca1F2steumZ57zOeheGQdiqo50O6KHjm+WgImmV92IFPUTU6eiaJsrTw=="], - "@iconify-json/humbleicons": ["@iconify-json/humbleicons@1.2.6", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-B5Ayka2mYbT8BxltoOEebe8XPfq0vpt2vzTGt/WJmapsapaLfAm00KdSEgIJ58VcBPWPtPI94FQ/97Yi/RAtAw=="], + "@iconify-json/humbleicons": ["@iconify-json/humbleicons@1.2.12", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-RPD+hBExPr+r+AcunJH/NYrtFNBm/99HjhGlaMDxIXh5RMqD7HebE5oJS6TgrNoUHHuQZ2u1gHmg4vgjaptB+A=="], - "@iconify-json/ion": ["@iconify-json/ion@1.2.3", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-qV9zsuBFjCgU5WRFO2thhhmaw1wr1wpJMliuuwu7pOtFEEoMOPP45Q7edF+k8uYuouFq+94SlCMIsca+v9kt2g=="], + "@iconify-json/ion": ["@iconify-json/ion@1.2.6", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-JftEXKfjvJNn3SrGeSBrG/waRkjeTpLdMLNLwpAX4NgI14QgJoAeXEh2iZjNPqioAkeIgErX4Bi6mnFwpjk3BQ=="], "@iconify-json/mdi": ["@iconify-json/mdi@1.2.3", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-O3cLwbDOK7NNDf2ihaQOH5F9JglnulNDFV7WprU2dSoZu3h3cWH//h74uQAB87brHmvFVxIOkuBX2sZSzYhScg=="], - "@iconify/json": ["@iconify/json@2.2.335", "", { "dependencies": { "@iconify/types": "*", "pathe": "^1.1.2" } }, "sha512-EOUM9843cxiwA19cORaz6t+fpn1LhZr5la+Oot7gzt8M5SRjOqvXfMZKcc/VkytRHaaNd2y0dKhA8H7/sP1stQ=="], + "@iconify/json": ["@iconify/json@2.2.392", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.0" } }, "sha512-WkkQIDpmgetgvIn1jso6XKY3S5Pf9L6QD1J2RNLeiF+jzdouyayoRm2LLxe4dmnp9i3Cbf8w7oRuaVlhwK8Xtg=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], @@ -686,11 +700,11 @@ "@intlify/bundle-utils": ["@intlify/bundle-utils@10.0.1", "", { "dependencies": { "@intlify/message-compiler": "^11.1.2", "@intlify/shared": "^11.1.2", "acorn": "^8.8.2", "escodegen": "^2.1.0", "estree-walker": "^2.0.2", "jsonc-eslint-parser": "^2.3.0", "mlly": "^1.2.0", "source-map-js": "^1.0.1", "yaml-eslint-parser": "^1.2.2" } }, "sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ=="], - "@intlify/core-base": ["@intlify/core-base@9.13.1", "", { "dependencies": { "@intlify/message-compiler": "9.13.1", "@intlify/shared": "9.13.1" } }, "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w=="], + "@intlify/core-base": ["@intlify/core-base@9.14.5", "", { "dependencies": { "@intlify/message-compiler": "9.14.5", "@intlify/shared": "9.14.5" } }, "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA=="], "@intlify/eslint-plugin-vue-i18n": ["@intlify/eslint-plugin-vue-i18n@1.4.1", "", { "dependencies": { "@eslint/eslintrc": "^1.2.0", "@intlify/core-base": "^9.1.9", "@intlify/message-compiler": "^9.1.9", "debug": "^4.3.1", "glob": "^7.1.3", "ignore": "^5.0.5", "is-language-code": "^3.1.0", "js-yaml": "^4.0.0", "json5": "^2.1.3", "jsonc-eslint-parser": "^2.0.0", "lodash": "^4.17.11", "parse5": "^6.0.0", "semver": "^7.3.4", "vue-eslint-parser": "^8.0.0", "yaml-eslint-parser": "^0.5.0" }, "peerDependencies": { "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-vnhwxcUTYCL/tCeBkXMDz959DVHNaDd3SRt3jdyX5ZwHaSSx93aD7kZV7ZmJpq4lZlq7Q1eVRGhpmpTNGdvU9w=="], - "@intlify/message-compiler": ["@intlify/message-compiler@9.13.1", "", { "dependencies": { "@intlify/shared": "9.13.1", "source-map-js": "^1.0.2" } }, "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w=="], + "@intlify/message-compiler": ["@intlify/message-compiler@9.14.5", "", { "dependencies": { "@intlify/shared": "9.14.5", "source-map-js": "^1.0.2" } }, "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ=="], "@intlify/shared": ["@intlify/shared@9.13.1", "", {}, "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ=="], @@ -698,7 +712,7 @@ "@intlify/vue-i18n-extensions": ["@intlify/vue-i18n-extensions@8.0.0", "", { "dependencies": { "@babel/parser": "^7.24.6", "@intlify/shared": "^10.0.0", "@vue/compiler-dom": "^3.2.45", "vue-i18n": "^10.0.0" }, "peerDependencies": { "vue": "^3.0.0" }, "optionalPeers": ["vue"] }, "sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/cliui": ["@isaacs/cliui@https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }], "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], @@ -708,17 +722,29 @@ "@jest/core": ["@jest/core@27.5.1", "", { "dependencies": { "@jest/console": "^27.5.1", "@jest/reporters": "^27.5.1", "@jest/test-result": "^27.5.1", "@jest/transform": "^27.5.1", "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "jest-changed-files": "^27.5.1", "jest-config": "^27.5.1", "jest-haste-map": "^27.5.1", "jest-message-util": "^27.5.1", "jest-regex-util": "^27.5.1", "jest-resolve": "^27.5.1", "jest-resolve-dependencies": "^27.5.1", "jest-runner": "^27.5.1", "jest-runtime": "^27.5.1", "jest-snapshot": "^27.5.1", "jest-util": "^27.5.1", "jest-validate": "^27.5.1", "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"] }, "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ=="], - "@jest/create-cache-key-function": ["@jest/create-cache-key-function@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3" } }, "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA=="], + "@jest/create-cache-key-function": ["@jest/create-cache-key-function@30.0.5", "", { "dependencies": { "@jest/types": "30.0.5" } }, "sha512-W1kmkwPq/WTMQWgvbzWSCbXSqvjI6rkqBQCxuvYmd+g6o4b5gHP98ikfh/Ei0SKzHvWdI84TOXp0hRcbpr8Q0w=="], + + "@jest/diff-sequences": ["@jest/diff-sequences@30.0.1", "", {}, "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw=="], "@jest/environment": ["@jest/environment@27.5.1", "", { "dependencies": { "@jest/fake-timers": "^27.5.1", "@jest/types": "^27.5.1", "@types/node": "*", "jest-mock": "^27.5.1" } }, "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA=="], + "@jest/expect": ["@jest/expect@30.2.0", "", { "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" } }, "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA=="], + + "@jest/expect-utils": ["@jest/expect-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0" } }, "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA=="], + "@jest/fake-timers": ["@jest/fake-timers@27.5.1", "", { "dependencies": { "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", "jest-message-util": "^27.5.1", "jest-mock": "^27.5.1", "jest-util": "^27.5.1" } }, "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ=="], + "@jest/get-type": ["@jest/get-type@30.1.0", "", {}, "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA=="], + "@jest/globals": ["@jest/globals@27.5.1", "", { "dependencies": { "@jest/environment": "^27.5.1", "@jest/types": "^27.5.1", "expect": "^27.5.1" } }, "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q=="], + "@jest/pattern": ["@jest/pattern@30.0.1", "", { "dependencies": { "@types/node": "*", "jest-regex-util": "30.0.1" } }, "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA=="], + "@jest/reporters": ["@jest/reporters@27.5.1", "", { "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^27.5.1", "@jest/test-result": "^27.5.1", "@jest/transform": "^27.5.1", "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", "jest-haste-map": "^27.5.1", "jest-resolve": "^27.5.1", "jest-util": "^27.5.1", "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", "v8-to-istanbul": "^8.1.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"] }, "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw=="], - "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + "@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + + "@jest/snapshot-utils": ["@jest/snapshot-utils@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" } }, "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug=="], "@jest/source-map": ["@jest/source-map@27.5.1", "", { "dependencies": { "callsites": "^3.0.0", "graceful-fs": "^4.2.9", "source-map": "^0.6.0" } }, "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg=="], @@ -732,19 +758,21 @@ "@josephg/resolvable": ["@josephg/resolvable@1.0.1", "", {}, "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], - "@jridgewell/source-map": ["@jridgewell/source-map@0.3.6", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], + "@keyv/bigmap": ["@keyv/bigmap@1.0.2", "", { "dependencies": { "hookified": "^1.12.1" } }, "sha512-KR03xkEZlAZNF4IxXgVXb+uNIVNvwdh8UwI0cnc7WI6a+aQcDp8GL80qVfeB4E5NpsKJzou5jU0r6yLSSbMOtA=="], - "@keyv/serialize": ["@keyv/serialize@1.0.3", "", { "dependencies": { "buffer": "^6.0.3" } }, "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g=="], + "@keyv/serialize": ["@keyv/serialize@1.1.1", "", {}, "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA=="], "@ladjs/country-language": ["@ladjs/country-language@1.0.3", "", {}, "sha512-FJROu9/hh4eqVAGDyfL8vpv6Vb0qKHX1ozYLRZ+beUzD5xFf+3r0J+SVIWKviEa7W524Qvqou+ta1WrsRgzxGw=="], @@ -760,45 +788,47 @@ "@messageformat/runtime": ["@messageformat/runtime@3.0.1", "", { "dependencies": { "make-plural": "^7.0.0" } }, "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg=="], - "@morev/utils": ["@morev/utils@3.12.1", "", { "dependencies": { "fast-copy": "^3.0.2", "fast-equals": "^5.0.1", "ohash": "^1.1.4", "type-fest": "^4.26.1" } }, "sha512-Qkj3ZP6KvEOYEx2GkM7Pffq7uHwgF6kOzVMLb8JTjV4Tb+qTLsZHk/2XF7lrm9VUZIDN17d7pXpZC6BzlR3ryw=="], + "@morev/utils": ["@morev/utils@3.13.1", "", { "dependencies": { "fast-copy": "^3.0.2", "fast-equals": "^5.0.1", "ohash": "^1.1.4", "type-fest": "^4.26.1" } }, "sha512-dNsXp9Ef9cuPIGmL6igYQx0VeHPoZQ9Kp6M7lLnJ2WglMFpoy5gNw2WAldquEsJ0m+sR1DTOLfrSpWvF/wMVDw=="], "@morev/vue-transitions": ["@morev/vue-transitions@3.0.5", "", { "dependencies": { "@morev/utils": "^3.11.1", "@nuxt/kit": "^3.13.2" }, "peerDependencies": { "vue": "^2.6.14 || >=3" }, "bin": { "vue-transitions-version-fix": "bin/fix.js", "vue-transitions-version-switch": "bin/switch.js" } }, "sha512-V+2HGHBb5MSOa0GGZ7V1wb3AExr4XcNLl98txdGNTsnhbqy4JRaFMaIsdo4zdaD9ShRZgBSZyZbujabxS50DSw=="], - "@napi-rs/nice": ["@napi-rs/nice@1.0.1", "", { "optionalDependencies": { "@napi-rs/nice-android-arm-eabi": "1.0.1", "@napi-rs/nice-android-arm64": "1.0.1", "@napi-rs/nice-darwin-arm64": "1.0.1", "@napi-rs/nice-darwin-x64": "1.0.1", "@napi-rs/nice-freebsd-x64": "1.0.1", "@napi-rs/nice-linux-arm-gnueabihf": "1.0.1", "@napi-rs/nice-linux-arm64-gnu": "1.0.1", "@napi-rs/nice-linux-arm64-musl": "1.0.1", "@napi-rs/nice-linux-ppc64-gnu": "1.0.1", "@napi-rs/nice-linux-riscv64-gnu": "1.0.1", "@napi-rs/nice-linux-s390x-gnu": "1.0.1", "@napi-rs/nice-linux-x64-gnu": "1.0.1", "@napi-rs/nice-linux-x64-musl": "1.0.1", "@napi-rs/nice-win32-arm64-msvc": "1.0.1", "@napi-rs/nice-win32-ia32-msvc": "1.0.1", "@napi-rs/nice-win32-x64-msvc": "1.0.1" } }, "sha512-zM0mVWSXE0a0h9aKACLwKmD6nHcRiKrPpCfvaKqG1CqDEyjEawId0ocXxVzPMCAm6kkWr2P025msfxXEnt8UGQ=="], + "@napi-rs/nice": ["@napi-rs/nice@1.1.1", "", { "optionalDependencies": { "@napi-rs/nice-android-arm-eabi": "1.1.1", "@napi-rs/nice-android-arm64": "1.1.1", "@napi-rs/nice-darwin-arm64": "1.1.1", "@napi-rs/nice-darwin-x64": "1.1.1", "@napi-rs/nice-freebsd-x64": "1.1.1", "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", "@napi-rs/nice-linux-arm64-gnu": "1.1.1", "@napi-rs/nice-linux-arm64-musl": "1.1.1", "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", "@napi-rs/nice-linux-s390x-gnu": "1.1.1", "@napi-rs/nice-linux-x64-gnu": "1.1.1", "@napi-rs/nice-linux-x64-musl": "1.1.1", "@napi-rs/nice-openharmony-arm64": "1.1.1", "@napi-rs/nice-win32-arm64-msvc": "1.1.1", "@napi-rs/nice-win32-ia32-msvc": "1.1.1", "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw=="], - "@napi-rs/nice-android-arm-eabi": ["@napi-rs/nice-android-arm-eabi@1.0.1", "", { "os": "android", "cpu": "arm" }, "sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w=="], + "@napi-rs/nice-android-arm-eabi": ["@napi-rs/nice-android-arm-eabi@1.1.1", "", { "os": "android", "cpu": "arm" }, "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw=="], - "@napi-rs/nice-android-arm64": ["@napi-rs/nice-android-arm64@1.0.1", "", { "os": "android", "cpu": "arm64" }, "sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA=="], + "@napi-rs/nice-android-arm64": ["@napi-rs/nice-android-arm64@1.1.1", "", { "os": "android", "cpu": "arm64" }, "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw=="], - "@napi-rs/nice-darwin-arm64": ["@napi-rs/nice-darwin-arm64@1.0.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-91k3HEqUl2fsrz/sKkuEkscj6EAj3/eZNCLqzD2AA0TtVbkQi8nqxZCZDMkfklULmxLkMxuUdKe7RvG/T6s2AA=="], + "@napi-rs/nice-darwin-arm64": ["@napi-rs/nice-darwin-arm64@1.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A=="], - "@napi-rs/nice-darwin-x64": ["@napi-rs/nice-darwin-x64@1.0.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ=="], + "@napi-rs/nice-darwin-x64": ["@napi-rs/nice-darwin-x64@1.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ=="], - "@napi-rs/nice-freebsd-x64": ["@napi-rs/nice-freebsd-x64@1.0.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw=="], + "@napi-rs/nice-freebsd-x64": ["@napi-rs/nice-freebsd-x64@1.1.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ=="], - "@napi-rs/nice-linux-arm-gnueabihf": ["@napi-rs/nice-linux-arm-gnueabihf@1.0.1", "", { "os": "linux", "cpu": "arm" }, "sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q=="], + "@napi-rs/nice-linux-arm-gnueabihf": ["@napi-rs/nice-linux-arm-gnueabihf@1.1.1", "", { "os": "linux", "cpu": "arm" }, "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg=="], - "@napi-rs/nice-linux-arm64-gnu": ["@napi-rs/nice-linux-arm64-gnu@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA=="], + "@napi-rs/nice-linux-arm64-gnu": ["@napi-rs/nice-linux-arm64-gnu@1.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ=="], - "@napi-rs/nice-linux-arm64-musl": ["@napi-rs/nice-linux-arm64-musl@1.0.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw=="], + "@napi-rs/nice-linux-arm64-musl": ["@napi-rs/nice-linux-arm64-musl@1.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg=="], - "@napi-rs/nice-linux-ppc64-gnu": ["@napi-rs/nice-linux-ppc64-gnu@1.0.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q=="], + "@napi-rs/nice-linux-ppc64-gnu": ["@napi-rs/nice-linux-ppc64-gnu@1.1.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg=="], - "@napi-rs/nice-linux-riscv64-gnu": ["@napi-rs/nice-linux-riscv64-gnu@1.0.1", "", { "os": "linux", "cpu": "none" }, "sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig=="], + "@napi-rs/nice-linux-riscv64-gnu": ["@napi-rs/nice-linux-riscv64-gnu@1.1.1", "", { "os": "linux", "cpu": "none" }, "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw=="], - "@napi-rs/nice-linux-s390x-gnu": ["@napi-rs/nice-linux-s390x-gnu@1.0.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg=="], + "@napi-rs/nice-linux-s390x-gnu": ["@napi-rs/nice-linux-s390x-gnu@1.1.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ=="], - "@napi-rs/nice-linux-x64-gnu": ["@napi-rs/nice-linux-x64-gnu@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA=="], + "@napi-rs/nice-linux-x64-gnu": ["@napi-rs/nice-linux-x64-gnu@1.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg=="], - "@napi-rs/nice-linux-x64-musl": ["@napi-rs/nice-linux-x64-musl@1.0.1", "", { "os": "linux", "cpu": "x64" }, "sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ=="], + "@napi-rs/nice-linux-x64-musl": ["@napi-rs/nice-linux-x64-musl@1.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw=="], - "@napi-rs/nice-win32-arm64-msvc": ["@napi-rs/nice-win32-arm64-msvc@1.0.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg=="], + "@napi-rs/nice-openharmony-arm64": ["@napi-rs/nice-openharmony-arm64@1.1.1", "", { "os": "none", "cpu": "arm64" }, "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ=="], - "@napi-rs/nice-win32-ia32-msvc": ["@napi-rs/nice-win32-ia32-msvc@1.0.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw=="], + "@napi-rs/nice-win32-arm64-msvc": ["@napi-rs/nice-win32-arm64-msvc@1.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA=="], - "@napi-rs/nice-win32-x64-msvc": ["@napi-rs/nice-win32-x64-msvc@1.0.1", "", { "os": "win32", "cpu": "x64" }, "sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg=="], + "@napi-rs/nice-win32-ia32-msvc": ["@napi-rs/nice-win32-ia32-msvc@1.1.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" } }, "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA=="], + "@napi-rs/nice-win32-x64-msvc": ["@napi-rs/nice-win32-x64-msvc@1.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -806,67 +836,67 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@nuxt/kit": ["@nuxt/kit@3.17.2", "", { "dependencies": { "c12": "^3.0.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.5", "ignore": "^7.0.4", "jiti": "^2.4.2", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.7.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.1.0", "scule": "^1.3.0", "semver": "^7.7.1", "std-env": "^3.9.0", "tinyglobby": "^0.2.13", "ufo": "^1.6.1", "unctx": "^2.4.1", "unimport": "^5.0.1", "untyped": "^2.0.0" } }, "sha512-Mz2Ni8iUwty5LBs3LepUL43rI2xXbuAz3Cqq37L9frOD2QI2tQUtasYaSoKk6U7nvYzuW2z/2b3YOLkMNi/k2w=="], + "@nuxt/kit": ["@nuxt/kit@3.19.3", "", { "dependencies": { "c12": "^3.3.0", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.2", "std-env": "^3.9.0", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "unimport": "^5.4.1", "untyped": "^2.0.0" } }, "sha512-ze46EW5xW+UxDvinvPkYt2MzR355Az1lA3bpX8KDialgnCwr+IbkBij/udbUEC6ZFbidPkfK1eKl4ESN7gMY+w=="], "@one-ini/wasm": ["@one-ini/wasm@0.1.1", "", {}, "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="], - "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@5.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hXem5ZAguS7IlSiHg/LK0tEfLj4eUo+9U6DaFwwBEGd0L0VIF9LmuiHydRyOrdnnmi9iAAFMAn/wl2cUoiuruA=="], + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@5.3.0", "", {}, "sha512-hXem5ZAguS7IlSiHg/LK0tEfLj4eUo+9U6DaFwwBEGd0L0VIF9LmuiHydRyOrdnnmi9iAAFMAn/wl2cUoiuruA=="], - "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@5.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-wgSwfsZkRbuYCIBLxeg1bYrtKnirAy+IJF0lwfz4z08clgdNBDbfGECJe/cd0csIZPpRcvPFe8317yf31sWhtA=="], + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@5.3.0", "", {}, "sha512-wgSwfsZkRbuYCIBLxeg1bYrtKnirAy+IJF0lwfz4z08clgdNBDbfGECJe/cd0csIZPpRcvPFe8317yf31sWhtA=="], - "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@5.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kzeE2WHgcRMmWjB071RdwEV5Pwke4o0WWslCKoh8if1puvxIxfzu3o7g6P2+v77BP5qop4cri+uvLABSO0WZjg=="], + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@5.3.0", "", {}, "sha512-kzeE2WHgcRMmWjB071RdwEV5Pwke4o0WWslCKoh8if1puvxIxfzu3o7g6P2+v77BP5qop4cri+uvLABSO0WZjg=="], - "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@5.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-I8np34yZP/XfIkZNDbw3rweqVgfjmHYpNX3xnJZWg+f4mgO9/UNWBwetSaqXeDZqvIch/aHak+q4HVrQhQKCqg=="], + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@5.3.0", "", {}, "sha512-I8np34yZP/XfIkZNDbw3rweqVgfjmHYpNX3xnJZWg+f4mgO9/UNWBwetSaqXeDZqvIch/aHak+q4HVrQhQKCqg=="], - "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@5.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-u2ndfeEUrW898eXM+qPxIN8TvTPjI90NDQBRgaxxkOfNw3xaotloeiZGz5+Yzlfxgvxr9DY9FdYkqhUhSnGhOw=="], + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@5.3.0", "", {}, "sha512-u2ndfeEUrW898eXM+qPxIN8TvTPjI90NDQBRgaxxkOfNw3xaotloeiZGz5+Yzlfxgvxr9DY9FdYkqhUhSnGhOw=="], - "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@5.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-TzbjmFkcnESGuVItQ2diKacX8vu5G0bH3BHmIlmY4OSRLyoAlrJFwGKAHmh6C9+Amfcjo2rx8vdm7swzmsGC6Q=="], + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@5.3.0", "", {}, "sha512-TzbjmFkcnESGuVItQ2diKacX8vu5G0bH3BHmIlmY4OSRLyoAlrJFwGKAHmh6C9+Amfcjo2rx8vdm7swzmsGC6Q=="], - "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@5.3.0", "", { "os": "linux", "cpu": "none" }, "sha512-NH3pjAqh8nuN29iRuRfTY42Vn03ctoR9VE8llfoUKUfhHUjFHYOXK5VSkhjj1usG8AeuesvqrQnLptCRQVTi/Q=="], + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@5.3.0", "", {}, "sha512-NH3pjAqh8nuN29iRuRfTY42Vn03ctoR9VE8llfoUKUfhHUjFHYOXK5VSkhjj1usG8AeuesvqrQnLptCRQVTi/Q=="], - "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@5.3.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-tuZtkK9sJYh2MC2uhol1M/8IMTB6ZQ5jmqP2+k5XNXnOb/im94Y5uV/u2lXwVyIuKHZZHtr+0d1HrOiNahoKpw=="], + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@5.3.0", "", {}, "sha512-tuZtkK9sJYh2MC2uhol1M/8IMTB6ZQ5jmqP2+k5XNXnOb/im94Y5uV/u2lXwVyIuKHZZHtr+0d1HrOiNahoKpw=="], - "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@5.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-VzhPYmZCtoES/ThcPdGSmMop7JlwgqtSvlgtKCW15ByV2JKyl8kHAHnPSBfpIooXb0ehFnRdxFtL9qtAEWy01g=="], + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@5.3.0", "", {}, "sha512-VzhPYmZCtoES/ThcPdGSmMop7JlwgqtSvlgtKCW15ByV2JKyl8kHAHnPSBfpIooXb0ehFnRdxFtL9qtAEWy01g=="], - "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@5.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Hi39cWzul24rGljN4Vf1lxjXzQdCrdxO5oCT7KJP4ndSlqIUODJnfnMAP1YhcnIRvNvk+5E6sZtnEmFUd/4d8Q=="], + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@5.3.0", "", {}, "sha512-Hi39cWzul24rGljN4Vf1lxjXzQdCrdxO5oCT7KJP4ndSlqIUODJnfnMAP1YhcnIRvNvk+5E6sZtnEmFUd/4d8Q=="], - "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@5.3.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.9" }, "cpu": "none" }, "sha512-ddujvHhP3chmHnSXRlkPVUeYj4/B7eLZwL4yUid+df3WCbVh6DgoT9RmllZn21AhxgKtMdekDdyVJYKFd8tl4A=="], + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@5.3.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.9" } }, "sha512-ddujvHhP3chmHnSXRlkPVUeYj4/B7eLZwL4yUid+df3WCbVh6DgoT9RmllZn21AhxgKtMdekDdyVJYKFd8tl4A=="], - "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@5.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-j1YYPLvUkMVNKmIFQZZJ7q6Do4cI3htUnyxNLwDSBVhSohvPIK2VG+IdtOAlWZGa7v+phEZsHfNbXVwB0oPYFQ=="], + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@5.3.0", "", {}, "sha512-j1YYPLvUkMVNKmIFQZZJ7q6Do4cI3htUnyxNLwDSBVhSohvPIK2VG+IdtOAlWZGa7v+phEZsHfNbXVwB0oPYFQ=="], - "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@5.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LT9eOPPUqfZscQRd5mc08RBeDWOQf+dnOrKnanMallTGPe6g7+rcAlFTA8SWoJbcD45PV8yArFtCmSQSpzHZmg=="], + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@5.3.0", "", {}, "sha512-LT9eOPPUqfZscQRd5mc08RBeDWOQf+dnOrKnanMallTGPe6g7+rcAlFTA8SWoJbcD45PV8yArFtCmSQSpzHZmg=="], "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], - "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], + "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", {}, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], - "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], + "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", {}, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], - "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], + "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", {}, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], - "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], + "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", {}, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], - "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], + "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", {}, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], - "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], + "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", {}, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], - "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], + "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", {}, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], - "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], + "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", {}, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], - "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], + "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", {}, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], - "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], + "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", {}, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], - "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], + "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", {}, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], - "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], + "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", {}, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + "@pkgjs/parseargs": ["@pkgjs/parseargs@https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", {}], - "@pkgr/core": ["@pkgr/core@0.2.4", "", {}, "sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw=="], + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], @@ -890,52 +920,54 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.2", "", { "os": "android", "cpu": "arm" }, "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.4", "", { "os": "android", "cpu": "arm" }, "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.2", "", { "os": "android", "cpu": "arm64" }, "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.4", "", { "os": "android", "cpu": "arm64" }, "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.40.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.40.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.40.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.40.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.40.2", "", { "os": "linux", "cpu": "arm" }, "sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.4", "", { "os": "linux", "cpu": "arm" }, "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.40.2", "", { "os": "linux", "cpu": "arm" }, "sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.4", "", { "os": "linux", "cpu": "arm" }, "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.40.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.40.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g=="], - "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.40.2", "", { "os": "linux", "cpu": "none" }, "sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ=="], - "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.40.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.40.2", "", { "os": "linux", "cpu": "none" }, "sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.40.2", "", { "os": "linux", "cpu": "none" }, "sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.40.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.40.2", "", { "os": "linux", "cpu": "x64" }, "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.4", "", { "os": "linux", "cpu": "x64" }, "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.40.2", "", { "os": "linux", "cpu": "x64" }, "sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.4", "", { "os": "linux", "cpu": "x64" }, "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.40.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.4", "", { "os": "none", "cpu": "arm64" }, "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.40.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.2", "", { "os": "win32", "cpu": "x64" }, "sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.4", "", { "os": "win32", "cpu": "x64" }, "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.4", "", { "os": "win32", "cpu": "x64" }, "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], - "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], - "@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.6.0", "", { "dependencies": { "domhandler": "^4.2.0", "selderee": "^0.6.0" } }, "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA=="], "@sideway/address": ["@sideway/address@4.1.5", "", { "dependencies": { "@hapi/hoek": "^9.0.0" } }, "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q=="], @@ -944,7 +976,7 @@ "@sideway/pinpoint": ["@sideway/pinpoint@2.0.0", "", {}, "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="], - "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + "@sinclair/typebox": ["@sinclair/typebox@0.34.38", "", {}, "sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA=="], "@sindresorhus/is": ["@sindresorhus/is@5.6.0", "", {}, "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="], @@ -952,48 +984,50 @@ "@sinonjs/fake-timers": ["@sinonjs/fake-timers@8.1.0", "", { "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg=="], - "@sqltools/formatter": ["@sqltools/formatter@1.2.5", "", {}, "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw=="], + "@sqltools/formatter": ["@sqltools/formatter@https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", {}], - "@swc-node/core": ["@swc-node/core@1.13.3", "", { "peerDependencies": { "@swc/core": ">= 1.4.13", "@swc/types": ">= 0.1" } }, "sha512-OGsvXIid2Go21kiNqeTIn79jcaX4l0G93X2rAnas4LFoDyA9wAwVK7xZdm+QsKoMn5Mus2yFLCc4OtX2dD/PWA=="], + "@swc-node/core": ["@swc-node/core@1.13.3", "", {}, "sha512-OGsvXIid2Go21kiNqeTIn79jcaX4l0G93X2rAnas4LFoDyA9wAwVK7xZdm+QsKoMn5Mus2yFLCc4OtX2dD/PWA=="], - "@swc-node/register": ["@swc-node/register@1.10.10", "", { "dependencies": { "@swc-node/core": "^1.13.3", "@swc-node/sourcemap-support": "^0.5.1", "colorette": "^2.0.20", "debug": "^4.3.5", "oxc-resolver": "^5.0.0", "pirates": "^4.0.6", "tslib": "^2.6.3" }, "peerDependencies": { "@swc/core": ">= 1.4.13", "typescript": ">= 4.3" } }, "sha512-jYWaI2WNEKz8KZL3sExd2KVL1JMma1/J7z+9iTpv0+fRN7LGMF8VTGGuHI2bug/ztpdZU1G44FG/Kk6ElXL9CQ=="], + "@swc-node/register": ["@swc-node/register@1.10.10", "", { "dependencies": { "@swc-node/core": "^1.13.3", "@swc-node/sourcemap-support": "^0.5.1", "colorette": "^2.0.20", "debug": "^4.3.5", "oxc-resolver": "^5.0.0", "pirates": "^4.0.6", "tslib": "^2.6.3" } }, "sha512-jYWaI2WNEKz8KZL3sExd2KVL1JMma1/J7z+9iTpv0+fRN7LGMF8VTGGuHI2bug/ztpdZU1G44FG/Kk6ElXL9CQ=="], "@swc-node/sourcemap-support": ["@swc-node/sourcemap-support@0.5.1", "", { "dependencies": { "source-map-support": "^0.5.21", "tslib": "^2.6.3" } }, "sha512-JxIvIo/Hrpv0JCHSyRpetAdQ6lB27oFYhv0PKCNf1g2gUXOjpeR1exrXccRxLMuAV5WAmGFBwRnNOJqN38+qtg=="], - "@swc/cli": ["@swc/cli@0.7.7", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "fast-glob": "^3.2.5", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-j4yYm9bx3pxWofaJKX1BFwj/3ngUDynN4UIQ2Xd2h0h/7Gt7zkReBTpDN7g5S13mgAYxacaTHTOUsz18097E8w=="], + "@swc/cli": ["@swc/cli@0.7.8", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3", "tinyglobby": "^0.2.13" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-27Ov4rm0s2C6LLX+NDXfDVB69LGs8K94sXtFhgeUyQ4DBywZuCgTBu2loCNHRr8JhT9DeQvJM5j9FAu/THbo4w=="], - "@swc/core": ["@swc/core@1.12.4", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.23" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.12.4", "@swc/core-darwin-x64": "1.12.4", "@swc/core-linux-arm-gnueabihf": "1.12.4", "@swc/core-linux-arm64-gnu": "1.12.4", "@swc/core-linux-arm64-musl": "1.12.4", "@swc/core-linux-x64-gnu": "1.12.4", "@swc/core-linux-x64-musl": "1.12.4", "@swc/core-win32-arm64-msvc": "1.12.4", "@swc/core-win32-ia32-msvc": "1.12.4", "@swc/core-win32-x64-msvc": "1.12.4" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-hn30ebV4njAn0NAUM+3a0qCF+MJgqTNSrfA/hUAbC6TVjOQy2OYGQwkUvCu/V7S2+rZxrUsTpKOnZ7qqECZV9Q=="], + "@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="], - "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.12.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HihKfeitjZU2ab94Zf893sxzFryLKX0TweGsNXXOLNtkSMLw50auuYfpRM0BOL9/uXXtuCWgRIF6P030SAX5xQ=="], + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ=="], - "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.12.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-meYCXHyYb6RDdu2N5PNAf0EelyxPBFhRcVo4kBFLuvuNb0m6EUg///VWy8MUMXq9/s9uzGS9kJVXXdRdr/d6FA=="], + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.13.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng=="], - "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.12.4", "", { "os": "linux", "cpu": "arm" }, "sha512-szfDbf7mE8V64of0q/LSqbk+em+T+TD3uqnH40Z7Qu/aL8vi5CHgyLjWG2SLkLLpyjgkAUF6AKrupgnBYcC2NA=="], + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.13.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ=="], - "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.12.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-n0IY76w+Scx8m3HIVRvLkoResuwsQgjDfAk9bxn99dq4leQO+mE0fkPl0Yw/1BIsPh+kxGfopIJH9zsZ1Z2YrA=="], + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw=="], - "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.12.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-wE5jmFi5cEQyLy8WmCWmNwfKETrnzy2D8YNi/xpYWpLPWqPhcelpa6tswkfYlbsMmmOh7hQNoTba1QdGu0jvHQ=="], + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ=="], - "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.12.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6S50Xd/7ePjEwrXyHMxpKTZ+KBrgUwMA8hQPbArUOwH4S5vHBr51heL0iXbUkppn1bkSr0J0IbOove5hzn+iqQ=="], + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA=="], - "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.12.4", "", { "os": "linux", "cpu": "x64" }, "sha512-hbYRyaHhC13vYKuGG5BrAG5fjjWEQFfQetuFp/4QKEoXDzdnabJoixxWTQACDL3m0JW32nJ+gUzsYIPtFYkwXg=="], + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q=="], - "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.12.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-e6EbfjPL8GA/bb1lc9Omtxjlz+1ThTsAuBsy4Q3Kpbuh6B3jclg8KzxU/6t91v23wG593mieTyR5f3Pr7X3AWw=="], + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.13.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw=="], - "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.12.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-RG2FzmllBTUf4EksANlIvLckcBrLZEA0t13LIa6L213UZKQfEuDNHezqESgoVhJMg2S/tWauitATOCFgZNSmjg=="], + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.13.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw=="], - "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.12.4", "", { "os": "win32", "cpu": "x64" }, "sha512-oRHKnZlR83zaMeVUCmHENa4j5uNRAWbmEpjYbzRcfC45LPFNWKGWGAGERLx0u87XMUtTGqnVYxnBTHN/rzDHOw=="], + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.13.5", "", { "os": "win32", "cpu": "x64" }, "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q=="], "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], - "@swc/jest": ["@swc/jest@0.2.38", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@swc/counter": "^0.1.3", "jsonc-parser": "^3.2.0" }, "peerDependencies": { "@swc/core": "*" } }, "sha512-HMoZgXWMqChJwffdDjvplH53g9G2ALQes3HKXDEdliB/b85OQ0CTSbxG8VSeCwiAn7cOaDVEt4mwmZvbHcS52w=="], + "@swc/jest": ["@swc/jest@0.2.39", "", { "dependencies": { "@jest/create-cache-key-function": "^30.0.0", "@swc/counter": "^0.1.3", "jsonc-parser": "^3.2.0" } }, "sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA=="], - "@swc/types": ["@swc/types@0.1.23", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw=="], + "@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="], "@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="], + "@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="], + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], "@tootallnate/once": ["@tootallnate/once@1.1.2", "", {}, "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="], @@ -1006,7 +1040,7 @@ "@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="], "@types/accepts": ["@types/accepts@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ=="], @@ -1016,31 +1050,31 @@ "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], - "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="], + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/body-parser": ["@types/body-parser@1.19.5", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg=="], + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], - "@types/content-disposition": ["@types/content-disposition@0.5.8", "", {}, "sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg=="], + "@types/content-disposition": ["@types/content-disposition@0.5.9", "", {}, "sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ=="], - "@types/cookies": ["@types/cookies@0.9.0", "", { "dependencies": { "@types/connect": "*", "@types/express": "*", "@types/keygrip": "*", "@types/node": "*" } }, "sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q=="], + "@types/cookies": ["@types/cookies@0.9.1", "", { "dependencies": { "@types/connect": "*", "@types/express": "*", "@types/keygrip": "*", "@types/node": "*" } }, "sha512-E/DPgzifH4sM1UMadJMWd6mO2jOd4g1Ejwzx8/uRCDpJis1IrlyQEcGAYEomtAqRYmD5ORbNXMeI9U0RiVGZbg=="], "@types/cors": ["@types/cors@2.8.10", "", {}, "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ=="], "@types/dotenv": ["@types/dotenv@8.2.3", "", { "dependencies": { "dotenv": "*" } }, "sha512-g2FXjlDX/cYuc5CiQvyU/6kkbP1JtmGzh0obW50zD7OKeILVL0NSpPWLXVfqoAGQjom2/SLLx9zHq0KXvD6mbw=="], - "@types/email-templates": ["@types/email-templates@10.0.4", "", { "dependencies": { "@types/html-to-text": "*", "@types/nodemailer": "*", "juice": "^8.0.0" } }, "sha512-8O2bdGPO6RYgH2DrnFAcuV++s+8KNA5e2Erjl6UxgKRVsBH9zXu2YLrLyOBRMn2VyEYmzgF+6QQUslpVhj0y/g=="], + "@types/email-templates": ["@types/email-templates@10.0.1", "", { "dependencies": { "@types/html-to-text": "*", "@types/nodemailer": "*", "juice": "^8.0.0" } }, "sha512-IHdgtoOUfMB4t5y5wgm8G0i2/U90GeJPxIEAViMaLlJPCJzaYSlVHXI8bx3qbgbD6gxyOsSRyrFvBSTgNEQc+g=="], "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], - "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="], + "@types/express": ["@types/express@4.17.23", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ=="], - "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="], + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.7", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg=="], "@types/faker": ["@types/faker@5.5.9", "", {}, "sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA=="], @@ -1060,7 +1094,7 @@ "@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.4", "", {}, "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="], - "@types/http-errors": ["@types/http-errors@2.0.4", "", {}, "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="], + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], "@types/i18n": ["@types/i18n@0.13.12", "", {}, "sha512-iAd2QjKh+0ToBXocmCS3m38GskiaGzmSV1MTQz2GaOraqSqBiLf46J7u3EGINl+st+Uk4lO3OL7QyIjTJlrWIg=="], @@ -1080,13 +1114,13 @@ "@types/keygrip": ["@types/keygrip@1.0.6", "", {}, "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ=="], - "@types/koa": ["@types/koa@2.15.0", "", { "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", "@types/cookies": "*", "@types/http-assert": "*", "@types/http-errors": "*", "@types/keygrip": "*", "@types/koa-compose": "*", "@types/node": "*" } }, "sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g=="], + "@types/koa": ["@types/koa@3.0.0", "", { "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", "@types/cookies": "*", "@types/http-assert": "*", "@types/http-errors": "^2", "@types/keygrip": "*", "@types/koa-compose": "*", "@types/node": "*" } }, "sha512-MOcVYdVYmkSutVHZZPh8j3+dAjLyR5Tl59CN0eKgpkE1h/LBSmPAsQQuWs+bKu7WtGNn+hKfJH9Gzml+PulmDg=="], "@types/koa-compose": ["@types/koa-compose@3.2.8", "", { "dependencies": { "@types/koa": "*" } }, "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA=="], - "@types/leaflet": ["@types/leaflet@1.9.17", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA=="], + "@types/leaflet": ["@types/leaflet@1.9.20", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-rooalPMlk61LCaLOvBF2VIf9M47HgMQqi5xQ9QRi7c8PkdIe0WrIi5IxXUXQjAdL0c+vcQ01mYWbthzmp9GHWw=="], - "@types/lodash": ["@types/lodash@4.17.16", "", {}, "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g=="], + "@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="], "@types/lodash.clonedeep": ["@types/lodash.clonedeep@4.5.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q=="], @@ -1094,27 +1128,27 @@ "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], - "@types/minimatch": ["@types/minimatch@5.1.2", "", {}, "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="], + "@types/minimatch": ["@types/minimatch@6.0.0", "", { "dependencies": { "minimatch": "*" } }, "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA=="], "@types/mysql": ["@types/mysql@2.15.27", "", { "dependencies": { "@types/node": "*" } }, "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA=="], "@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="], - "@types/node-fetch": ["@types/node-fetch@2.6.12", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="], + "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], "@types/nodemailer": ["@types/nodemailer@6.4.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww=="], "@types/prettier": ["@types/prettier@2.7.3", "", {}, "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA=="], - "@types/qs": ["@types/qs@6.9.18", "", {}, "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA=="], + "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], - "@types/semver": ["@types/semver@7.7.0", "", {}, "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA=="], + "@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="], - "@types/send": ["@types/send@0.17.4", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA=="], + "@types/send": ["@types/send@0.17.5", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w=="], - "@types/serve-static": ["@types/serve-static@1.15.7", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "*" } }, "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw=="], + "@types/serve-static": ["@types/serve-static@1.15.9", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA=="], "@types/sodium-native": ["@types/sodium-native@2.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-jZIg5ltGH1okmnH3FrLQsgwjcjOVozMSHwSiEm1/LpMekhOMHbQqp21P4H24mizh1BjwI6Q8qmphmD/HJuAqWg=="], @@ -1132,25 +1166,67 @@ "@types/zen-observable": ["@types/zen-observable@0.8.7", "", {}, "sha512-LKzNTjj+2j09wAo/vvVjzgw5qckJJzhdGgWHW7j69QIGdq/KnZrMAMIHQiWGl3Ccflh5/CudBAntTPYdprPltA=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0" } }, "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.0", "@typescript-eslint/types": "^8.46.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.32.0", "", {}, "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.0", "", { "dependencies": { "@typescript-eslint/types": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0" } }, "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.46.0", "", {}, "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.0", "@typescript-eslint/tsconfig-utils": "8.46.0", "@typescript-eslint/types": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@7.18.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.32.0", "", { "dependencies": { "@typescript-eslint/types": "8.32.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.0", "", { "dependencies": { "@typescript-eslint/types": "8.46.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "@vee-validate/i18n": ["@vee-validate/i18n@4.15.0", "", {}, "sha512-XAXoIhcgy4//9WBmxK/6Wnv14Bwkrka/0PMHPOxUhbc8y4QfdIRbyFWvxWZw2nzc6suHrFIePt1mBx91aTqIwg=="], + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], - "@vee-validate/rules": ["@vee-validate/rules@4.15.0", "", { "dependencies": { "vee-validate": "4.15.0" } }, "sha512-Cvll7r98O5tU6ew2AUifVpdhNnTkMTY7+D9N++J7apQXRXWfHMe4tNvjo4TJpKUPCtfLHbdTY/DCquDRc+uH4w=="], + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], - "@vee-validate/yup": ["@vee-validate/yup@4.15.0", "", { "dependencies": { "type-fest": "^4.8.3", "vee-validate": "4.15.0" }, "peerDependencies": { "yup": "^1.3.2" } }, "sha512-paK2ZdxZJRrUGwqaqf7KMNC+n5C7UGs7DofK7wZCza/zKT/QtFSxVYgopGoYYrbAfd6DpVmNpf/ouBuRdPBthA=="], + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], - "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.3", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg=="], + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + + "@vee-validate/i18n": ["@vee-validate/i18n@4.15.1", "", {}, "sha512-6ogEyxkoTr7IZk4EAUT0rD3pr34Nw/YEToez/c0DSlI1/cBeOpunSmGmoYPh32pmd3imxFPEawCB7IyFvRJSAw=="], + + "@vee-validate/rules": ["@vee-validate/rules@4.15.1", "", { "dependencies": { "vee-validate": "4.15.1" } }, "sha512-2TGXq2MYt21nT8ysuxyFY/LBVQDcMPKn1hY0w3uIDmG333vzBkOtXAylmvrS93AsJ7N5coHMJjcCGG4JxCO2hQ=="], + + "@vee-validate/yup": ["@vee-validate/yup@4.15.1", "", { "dependencies": { "type-fest": "^4.8.3", "vee-validate": "4.15.1" }, "peerDependencies": { "yup": "^1.3.2" } }, "sha512-+u6lI1IZftjHphj+mTCPJRruwBBwv1IKKCI1EFm6ipQroAPibkS5M8UNX+yeVYG5++ix6m1rsv4/SJvJJQTWJg=="], + + "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="], "@vitest/coverage-v8": ["@vitest/coverage-v8@2.1.9", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^0.2.3", "debug": "^4.3.7", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magic-string": "^0.30.12", "magicast": "^0.3.5", "std-env": "^3.8.0", "test-exclude": "^7.0.1", "tinyrainbow": "^1.2.0" }, "peerDependencies": { "@vitest/browser": "2.1.9", "vitest": "2.1.9" }, "optionalPeers": ["@vitest/browser"] }, "sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ=="], @@ -1176,19 +1252,19 @@ "@vue/compat": ["@vue/compat@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-Q3xRdTPN4l+kddxU98REyUBgvc0meAo9CefCWE2lW8Fg3dyPn3vSCce52b338ihrJAx1RQQhO5wMWhJ/PAKUpA=="], - "@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/shared": "3.5.22", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ=="], - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], + "@vue/compiler-dom": ["@vue/compiler-dom@3.5.22", "", { "dependencies": { "@vue/compiler-core": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA=="], - "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], + "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/compiler-core": "3.5.22", "@vue/compiler-dom": "3.5.22", "@vue/compiler-ssr": "3.5.22", "@vue/shared": "3.5.22", "estree-walker": "^2.0.2", "magic-string": "^0.30.19", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ=="], - "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="], + "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.22", "", { "dependencies": { "@vue/compiler-dom": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww=="], "@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="], - "@vue/devtools-kit": ["@vue/devtools-kit@7.7.6", "", { "dependencies": { "@vue/devtools-shared": "^7.7.6", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA=="], + "@vue/devtools-kit": ["@vue/devtools-kit@7.7.7", "", { "dependencies": { "@vue/devtools-shared": "^7.7.7", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA=="], - "@vue/devtools-shared": ["@vue/devtools-shared@7.7.6", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA=="], + "@vue/devtools-shared": ["@vue/devtools-shared@7.7.7", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw=="], "@vue/eslint-config-prettier": ["@vue/eslint-config-prettier@10.2.0", "", { "dependencies": { "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2" }, "peerDependencies": { "eslint": ">= 8.21.0", "prettier": ">= 3.0.0" } }, "sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw=="], @@ -1200,7 +1276,7 @@ "@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], - "@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + "@vue/shared": ["@vue/shared@3.5.22", "", {}, "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w=="], "@vue/test-utils": ["@vue/test-utils@2.4.6", "", { "dependencies": { "js-beautify": "^1.14.9", "vue-component-type-helpers": "^2.0.0" } }, "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow=="], @@ -1242,23 +1318,23 @@ "@wry/trie": ["@wry/trie@0.5.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA=="], - "@xhmikosr/archive-type": ["@xhmikosr/archive-type@7.0.0", "", { "dependencies": { "file-type": "^19.0.0" } }, "sha512-sIm84ZneCOJuiy3PpWR5bxkx3HaNt1pqaN+vncUBZIlPZCq8ASZH+hBVdu5H8znR7qYC6sKwx+ie2Q7qztJTxA=="], + "@xhmikosr/archive-type": ["@xhmikosr/archive-type@7.1.0", "", { "dependencies": { "file-type": "^20.5.0" } }, "sha512-xZEpnGplg1sNPyEgFh0zbHxqlw5dtYg6viplmWSxUj12+QjU9SKu3U/2G73a15pEjLaOqTefNSZ1fOPUOT4Xgg=="], - "@xhmikosr/bin-check": ["@xhmikosr/bin-check@7.0.3", "", { "dependencies": { "execa": "^5.1.1", "isexe": "^2.0.0" } }, "sha512-4UnCLCs8DB+itHJVkqFp9Zjg+w/205/J2j2wNBsCEAm/BuBmtua2hhUOdAMQE47b1c7P9Xmddj0p+X1XVsfHsA=="], + "@xhmikosr/bin-check": ["@xhmikosr/bin-check@7.1.0", "", { "dependencies": { "execa": "^5.1.1", "isexe": "^2.0.0" } }, "sha512-y1O95J4mnl+6MpVmKfMYXec17hMEwE/yeCglFNdx+QvLLtP0yN4rSYcbkXnth+lElBuKKek2NbvOfOGPpUXCvw=="], - "@xhmikosr/bin-wrapper": ["@xhmikosr/bin-wrapper@13.0.5", "", { "dependencies": { "@xhmikosr/bin-check": "^7.0.3", "@xhmikosr/downloader": "^15.0.1", "@xhmikosr/os-filter-obj": "^3.0.0", "bin-version-check": "^5.1.0" } }, "sha512-DT2SAuHDeOw0G5bs7wZbQTbf4hd8pJ14tO0i4cWhRkIJfgRdKmMfkDilpaJ8uZyPA0NVRwasCNAmMJcWA67osw=="], + "@xhmikosr/bin-wrapper": ["@xhmikosr/bin-wrapper@13.2.0", "", { "dependencies": { "@xhmikosr/bin-check": "^7.1.0", "@xhmikosr/downloader": "^15.2.0", "@xhmikosr/os-filter-obj": "^3.0.0", "bin-version-check": "^5.1.0" } }, "sha512-t9U9X0sDPRGDk5TGx4dv5xiOvniVJpXnfTuynVKwHgtib95NYEw4MkZdJqhoSiz820D9m0o6PCqOPMXz0N9fIw=="], - "@xhmikosr/decompress": ["@xhmikosr/decompress@10.0.1", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.0.1", "@xhmikosr/decompress-tarbz2": "^8.0.1", "@xhmikosr/decompress-targz": "^8.0.1", "@xhmikosr/decompress-unzip": "^7.0.0", "graceful-fs": "^4.2.11", "make-dir": "^4.0.0", "strip-dirs": "^3.0.0" } }, "sha512-6uHnEEt5jv9ro0CDzqWlFgPycdE+H+kbJnwyxgZregIMLQ7unQSCNVsYG255FoqU8cP46DyggI7F7LohzEl8Ag=="], + "@xhmikosr/decompress": ["@xhmikosr/decompress@10.2.0", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.1.0", "@xhmikosr/decompress-tarbz2": "^8.1.0", "@xhmikosr/decompress-targz": "^8.1.0", "@xhmikosr/decompress-unzip": "^7.1.0", "graceful-fs": "^4.2.11", "strip-dirs": "^3.0.0" } }, "sha512-MmDBvu0+GmADyQWHolcZuIWffgfnuTo4xpr2I/Qw5Ox0gt+e1Be7oYqJM4te5ylL6mzlcoicnHVDvP27zft8tg=="], - "@xhmikosr/decompress-tar": ["@xhmikosr/decompress-tar@8.0.1", "", { "dependencies": { "file-type": "^19.0.0", "is-stream": "^2.0.1", "tar-stream": "^3.1.7" } }, "sha512-dpEgs0cQKJ2xpIaGSO0hrzz3Kt8TQHYdizHsgDtLorWajuHJqxzot9Hbi0huRxJuAGG2qiHSQkwyvHHQtlE+fg=="], + "@xhmikosr/decompress-tar": ["@xhmikosr/decompress-tar@8.1.0", "", { "dependencies": { "file-type": "^20.5.0", "is-stream": "^2.0.1", "tar-stream": "^3.1.7" } }, "sha512-m0q8x6lwxenh1CrsTby0Jrjq4vzW/QU1OLhTHMQLEdHpmjR1lgahGz++seZI0bXF3XcZw3U3xHfqZSz+JPP2Gg=="], - "@xhmikosr/decompress-tarbz2": ["@xhmikosr/decompress-tarbz2@8.0.2", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.0.1", "file-type": "^19.6.0", "is-stream": "^2.0.1", "seek-bzip": "^2.0.0", "unbzip2-stream": "^1.4.3" } }, "sha512-p5A2r/AVynTQSsF34Pig6olt9CvRj6J5ikIhzUd3b57pUXyFDGtmBstcw+xXza0QFUh93zJsmY3zGeNDlR2AQQ=="], + "@xhmikosr/decompress-tarbz2": ["@xhmikosr/decompress-tarbz2@8.1.0", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.0.1", "file-type": "^20.5.0", "is-stream": "^2.0.1", "seek-bzip": "^2.0.0", "unbzip2-stream": "^1.4.3" } }, "sha512-aCLfr3A/FWZnOu5eqnJfme1Z1aumai/WRw55pCvBP+hCGnTFrcpsuiaVN5zmWTR53a8umxncY2JuYsD42QQEbw=="], - "@xhmikosr/decompress-targz": ["@xhmikosr/decompress-targz@8.0.1", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.0.1", "file-type": "^19.0.0", "is-stream": "^2.0.1" } }, "sha512-mvy5AIDIZjQ2IagMI/wvauEiSNHhu/g65qpdM4EVoYHUJBAmkQWqcPJa8Xzi1aKVTmOA5xLJeDk7dqSjlHq8Mg=="], + "@xhmikosr/decompress-targz": ["@xhmikosr/decompress-targz@8.1.0", "", { "dependencies": { "@xhmikosr/decompress-tar": "^8.0.1", "file-type": "^20.5.0", "is-stream": "^2.0.1" } }, "sha512-fhClQ2wTmzxzdz2OhSQNo9ExefrAagw93qaG1YggoIz/QpI7atSRa7eOHv4JZkpHWs91XNn8Hry3CwUlBQhfPA=="], - "@xhmikosr/decompress-unzip": ["@xhmikosr/decompress-unzip@7.0.0", "", { "dependencies": { "file-type": "^19.0.0", "get-stream": "^6.0.1", "yauzl": "^3.1.2" } }, "sha512-GQMpzIpWTsNr6UZbISawsGI0hJ4KA/mz5nFq+cEoPs12UybAqZWKbyIaZZyLbJebKl5FkLpsGBkrplJdjvUoSQ=="], + "@xhmikosr/decompress-unzip": ["@xhmikosr/decompress-unzip@7.1.0", "", { "dependencies": { "file-type": "^20.5.0", "get-stream": "^6.0.1", "yauzl": "^3.1.2" } }, "sha512-oqTYAcObqTlg8owulxFTqiaJkfv2SHsxxxz9Wg4krJAHVzGWlZsU8tAB30R6ow+aHrfv4Kub6WQ8u04NWVPUpA=="], - "@xhmikosr/downloader": ["@xhmikosr/downloader@15.0.1", "", { "dependencies": { "@xhmikosr/archive-type": "^7.0.0", "@xhmikosr/decompress": "^10.0.1", "content-disposition": "^0.5.4", "defaults": "^3.0.0", "ext-name": "^5.0.0", "file-type": "^19.0.0", "filenamify": "^6.0.0", "get-stream": "^6.0.1", "got": "^13.0.0" } }, "sha512-fiuFHf3Dt6pkX8HQrVBsK0uXtkgkVlhrZEh8b7VgoDqFf+zrgFBPyrwCqE/3nDwn3hLeNz+BsrS7q3mu13Lp1g=="], + "@xhmikosr/downloader": ["@xhmikosr/downloader@15.2.0", "", { "dependencies": { "@xhmikosr/archive-type": "^7.1.0", "@xhmikosr/decompress": "^10.2.0", "content-disposition": "^0.5.4", "defaults": "^2.0.2", "ext-name": "^5.0.0", "file-type": "^20.5.0", "filenamify": "^6.0.0", "get-stream": "^6.0.1", "got": "^13.0.0" } }, "sha512-lAqbig3uRGTt0sHNIM4vUG9HoM+mRl8K28WuYxyXLCUT6pyzl4Y4i0LZ3jMEsCYZ6zjPZbO9XkG91OSTd4si7g=="], "@xhmikosr/os-filter-obj": ["@xhmikosr/os-filter-obj@3.0.0", "", { "dependencies": { "arch": "^3.0.0" } }, "sha512-siPY6BD5dQ2SZPl3I0OZBHL27ZqZvLEosObsZRQ1NUB8qcxegwt0T9eKtV96JMFQpIz1elhkzqOg4c/Ri6Dp9A=="], @@ -1274,17 +1350,19 @@ "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], - "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "acorn-globals": ["acorn-globals@6.0.0", "", { "dependencies": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" } }, "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg=="], + "acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="], + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], "admin": ["admin@workspace:admin"], - "agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], @@ -1304,7 +1382,7 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], + "ansis": ["ansis@https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", {}], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -1352,7 +1430,7 @@ "apollo-utilities": ["apollo-utilities@1.3.4", "", { "dependencies": { "@wry/equality": "^0.1.2", "fast-json-stable-stringify": "^2.0.0", "ts-invariant": "^0.4.0", "tslib": "^1.10.0" }, "peerDependencies": { "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" } }, "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig=="], - "app-root-path": ["app-root-path@3.1.0", "", {}, "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA=="], + "app-root-path": ["app-root-path@https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", {}], "arch": ["arch@3.0.0", "", {}, "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q=="], @@ -1366,7 +1444,7 @@ "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], - "array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], @@ -1398,7 +1476,7 @@ "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], - "auto-changelog": ["auto-changelog@2.5.0", "", { "dependencies": { "commander": "^7.2.0", "handlebars": "^4.7.7", "import-cwd": "^3.0.0", "node-fetch": "^2.6.1", "parse-github-url": "^1.0.3", "semver": "^7.3.5" }, "bin": { "auto-changelog": "src/index.js" } }, "sha512-UTnLjT7I9U2U/xkCUH5buDlp8C7g0SGChfib+iDrJkamcj5kaMqNKHNfbKJw1kthJUq8sUo3i3q2S6FzO/l/wA=="], + "auto-changelog": ["auto-changelog@https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.5.0.tgz", { "dependencies": { "commander": "^7.2.0", "handlebars": "^4.7.7", "import-cwd": "^3.0.0", "node-fetch": "^2.6.1", "parse-github-url": "^1.0.3", "semver": "^7.3.5" } }], "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="], @@ -1408,7 +1486,7 @@ "axios": ["axios@0.21.4", "", { "dependencies": { "follow-redirects": "^1.14.0" } }, "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="], - "b4a": ["b4a@1.6.7", "", {}, "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg=="], + "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], "babel-jest": ["babel-jest@27.5.1", "", { "dependencies": { "@jest/transform": "^27.5.1", "@jest/types": "^27.5.1", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg=="], @@ -1416,7 +1494,7 @@ "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@27.5.1", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.0.0", "@types/babel__traverse": "^7.0.6" } }, "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ=="], - "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.1.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw=="], + "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], "babel-preset-jest": ["babel-preset-jest@27.5.1", "", { "dependencies": { "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag=="], @@ -1430,19 +1508,21 @@ "bare-addon-resolve": ["bare-addon-resolve@1.9.4", "", { "dependencies": { "bare-module-resolve": "^1.10.0", "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-unn6Vy/Yke6F99vg/7tcrvM2KUvIhTNniaSqDbam4AWkd4NhvDVSrQiRYVlNzUV2P7SPobkCK7JFVxrJk9btCg=="], - "bare-events": ["bare-events@2.5.4", "", {}, "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA=="], + "bare-events": ["bare-events@2.7.0", "", {}, "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA=="], - "bare-module-resolve": ["bare-module-resolve@1.10.2", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-C9COe/GhWfVXKytW3DElTkiBU+Gb2OXeaVkdGdRB/lp26TVLESHkTGS876iceAGdvtPgohfp9nX8vXHGvN3++Q=="], + "bare-module-resolve": ["bare-module-resolve@1.11.1", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-DCxeT9i8sTs3vUMA3w321OX/oXtNEu5EjObQOnTmCdNp5RXHBAvAaBDHvAi9ta0q/948QPz+co6SsGi6aQMYRg=="], - "bare-os": ["bare-os@3.6.1", "", {}, "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g=="], + "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="], "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], "bare-semver": ["bare-semver@1.0.1", "", {}, "sha512-UtggzHLiTrmFOC/ogQ+Hy7VfoKoIwrP1UFcYtTxoCUdLtsIErT8+SWtOC2DH/snT9h+xDrcBEPcwKei1mzemgg=="], - "bare-url": ["bare-url@2.1.6", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-FgjDeR+/yDH34By4I0qB5NxAoWv7dOTYcOXwn73kr+c93HyC2lU6tnjifqUe33LKMJcDyCYPQjEAqgOQiXkE2Q=="], + "bare-url": ["bare-url@2.2.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA=="], - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "base64-js": ["base64-js@https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", {}], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.12", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ=="], "bignumber.js": ["bignumber.js@9.0.0", "", {}, "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="], @@ -1452,7 +1532,7 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - "birpc": ["birpc@2.3.0", "", {}, "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g=="], + "birpc": ["birpc@2.6.1", "", {}, "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ=="], "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], @@ -1464,23 +1544,23 @@ "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], - "bootstrap": ["bootstrap@5.3.6", "", { "peerDependencies": { "@popperjs/core": "^2.11.8" } }, "sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA=="], + "bootstrap": ["bootstrap@5.3.8", "", { "peerDependencies": { "@popperjs/core": "^2.11.8" } }, "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg=="], "bootstrap-vue-next": ["bootstrap-vue-next@0.26.8", "", { "peerDependencies": { "vue": "^3.5.13" } }, "sha512-2WolMPi4XB0J/736PPglDCIjUz2pwvOhu3SLjQYP0Rh5IncspMZMkUCa/H28Vh45xQadFtrYeBPyPF3JrpbadA=="], - "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], "browser-process-hrtime": ["browser-process-hrtime@1.0.0", "", {}, "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="], - "browserslist": ["browserslist@4.24.5", "", { "dependencies": { "caniuse-lite": "^1.0.30001716", "electron-to-chromium": "^1.5.149", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw=="], + "browserslist": ["browserslist@4.26.3", "", { "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w=="], "bs-logger": ["bs-logger@0.2.6", "", { "dependencies": { "fast-json-stable-stringify": "2.x" } }, "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog=="], "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], - "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "buffer": ["buffer@https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }], "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], @@ -1494,11 +1574,11 @@ "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - "c12": ["c12@3.0.3", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.4.7", "exsolve": "^1.0.4", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.1.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uC3MacKBb0Z15o5QWCHvHWj5Zv34pGQj9P+iXKSpTuSGFS0KKhUWf4t9AJ+gWjYOdmWCPEGpEzm8sS0iqbpo1w=="], + "c12": ["c12@3.3.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.2", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-K9ZkuyeJQeqLEyqldbYLG3wjqwpw4BVaAqvmxq3GYKK0b1A/yYQdIcJxkzAOWcNVWhJpRXAPfZFueekiY/L8Dw=="], "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "cacheable": ["cacheable@1.8.10", "", { "dependencies": { "hookified": "^1.8.1", "keyv": "^5.3.2" } }, "sha512-0ZnbicB/N2R6uziva8l6O6BieBklArWyiGx4GkwAhLKhSHyQtRfM9T1nx7HHuHDKkYB/efJQhz3QJ6x/YqoZzA=="], + "cacheable": ["cacheable@2.1.0", "", { "dependencies": { "@cacheable/memoize": "^2.0.3", "@cacheable/memory": "^2.0.3", "@cacheable/utils": "^2.1.0", "hookified": "^1.12.1", "keyv": "^5.5.3", "qified": "^0.5.0" } }, "sha512-zzL1BxdnqwD69JRT0dihnawAcLkBMwAH+hZSKjUzeBbPedVhk3qYPjRw9VOMYWwt5xRih5xd8S+3kEdGohZm/g=="], "cacheable-lookup": ["cacheable-lookup@7.0.0", "", {}, "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="], @@ -1516,9 +1596,9 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001717", "", {}, "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001748", "", {}, "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w=="], - "chai": ["chai@5.2.0", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw=="], + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -1550,7 +1630,7 @@ "clipboard-polyfill": ["clipboard-polyfill@4.1.1", "", {}, "sha512-nbvNLrcX0zviek5QHLFRAaLrx8y/s8+RF2stH43tuS+kP5XlHMrcD0UGBWq43Hwp6WuuK7KefRMP56S45ibZkA=="], - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "cliui": ["cliui@https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }], "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], @@ -1562,19 +1642,19 @@ "colord": ["colord@2.9.3", "", {}, "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="], - "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + "colorette": ["colorette@https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", {}], "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], - "commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "commander": ["commander@https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", {}], - "compact-encoding": ["compact-encoding@2.16.1", "", { "dependencies": { "b4a": "^1.3.0" } }, "sha512-vP39X4nwtesmZucaAxDg4wnudOoaJTSR+fikzi8VLVxbwLmcWXf3t0LxY0n2H1AMpdoQZ08lmUf4GY3XiDPnMQ=="], + "compact-encoding": ["compact-encoding@2.17.0", "", { "dependencies": { "b4a": "^1.3.0" } }, "sha512-A5mkpopiDqCddAHTmJ/VnP7JQ1MCytRbpi13zQJGsDcKN041B++2n8oUwxBn37C86gbIt/zIARaqLVy9vI9M5Q=="], "compact-encoding-net": ["compact-encoding-net@1.2.0", "", { "dependencies": { "compact-encoding": "^2.4.1" } }, "sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "concurrently": ["concurrently@9.1.2", "", { "dependencies": { "chalk": "^4.1.2", "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" }, "bin": { "concurrently": "dist/bin/concurrently.js", "conc": "dist/bin/concurrently.js" } }, "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ=="], + "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], @@ -1594,7 +1674,7 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -1604,7 +1684,7 @@ "core": ["core@workspace:core"], - "core-js-pure": ["core-js-pure@3.42.0", "", {}, "sha512-007bM04u91fF4kMgwom2I5cQxAFIy8jVulgr9eozILl/SZE53QOqnW/+vviC+wQWLv+AunBG+8Q0TLoeSsSxRQ=="], + "core-js-pure": ["core-js-pure@3.45.1", "", {}, "sha512-OHnWFKgTUshEU8MK+lOs1H8kC8GkTi9Z1tvNkxrCcw9wl3MJIO7q2ld77wjWn4/xuGrVu2X+nME1iIIPBSdyEQ=="], "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], @@ -1614,11 +1694,11 @@ "create-require": ["create-require@1.1.1", "", {}, "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="], - "cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "cross-env": ["cross-env@https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", { "dependencies": { "cross-spawn": "^7.0.1" } }], "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "cross-spawn": ["cross-spawn@https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }], "crypto-random-bigint": ["crypto-random-bigint@2.1.1", "", { "dependencies": { "uint-rng": "^1.2.1" } }, "sha512-96+FDrenXybkpnLML/60S8NcG32KgJ5Y8yvNNCYPW02r+ssoXFR5XKenuIQcHLWumnGj8UPqUUHBzXNrDGkDmQ=="], @@ -1628,7 +1708,7 @@ "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], - "css-what": ["css-what@6.1.0", "", {}, "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="], + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], @@ -1638,7 +1718,7 @@ "cssom": ["cssom@0.4.4", "", {}, "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="], - "cssstyle": ["cssstyle@4.3.1", "", { "dependencies": { "@asamuzakjp/css-color": "^3.1.2", "rrweb-cssom": "^0.8.0" } }, "sha512-ZgW+Jgdd7i52AaLYCriF8Mxqft0gD/R9i9wi6RWBhs1pqdPEzPjym7rvRKi397WmQFf3SlyUsszhw+VVCbx79Q=="], + "cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], @@ -1656,21 +1736,21 @@ "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], - "dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="], + "dayjs": ["dayjs@https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", {}], - "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "debugging-stream": ["debugging-stream@2.0.0", "", { "dependencies": { "streamx": "^2.12.4" } }, "sha512-xwfl6wB/3xc553uwtGnSa94jFxnGOc02C0WU2Nmzwr80gzeqn1FX4VcbvoKIhe8L/lPq4BTQttAbrTN94uN8rA=="], "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], - "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], + "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], - "dedent": ["dedent@1.6.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA=="], + "dedent": ["dedent@1.6.0", "", {}, "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA=="], "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], @@ -1680,7 +1760,7 @@ "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], - "defaults": ["defaults@3.0.0", "", {}, "sha512-RsqXDEAALjfRTro+IFNKpcPCt0/Cy2FqHSIlnomiJp9YGadpQnrtbRpSgN2+np21qHcIKiva4fiOQGjS9/qR/A=="], + "defaults": ["defaults@2.0.2", "", {}, "sha512-cuIw0PImdp76AOfgkjbW4VhQODRmNNcKR73vdCH5cLd/ifj7aamfoXvYgfGkEAjNJZ3ozMIy9Gu2LutUkGEPbA=="], "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], @@ -1704,7 +1784,7 @@ "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], - "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="], @@ -1750,7 +1830,7 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "eastasianwidth": ["eastasianwidth@https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", {}], "editorconfig": ["editorconfig@1.0.4", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q=="], @@ -1758,7 +1838,7 @@ "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "electron-to-chromium": ["electron-to-chromium@1.5.150", "", {}, "sha512-rOOkP2ZUMx1yL4fCxXQKDHQ8ZXwisb2OycOQVKHgvB3ZI4CvehOd4y2tfnnLDieJ3Zs1RL1Dlp3cMkyIn7nnXA=="], + "electron-to-chromium": ["electron-to-chromium@1.5.232", "", {}, "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg=="], "email-templates": ["email-templates@10.0.1", "", { "dependencies": { "@ladjs/i18n": "^8.0.1", "consolidate": "^0.16.0", "get-paths": "^0.0.7", "html-to-text": "^8.2.0", "juice": "^8.0.0", "lodash": "^4.17.21", "nodemailer": "^6.7.7", "preview-email": "^3.0.7" } }, "sha512-LNZKS0WW9XQkjuDZd/4p/1Q/pwqaqXOP3iDxTIVIQY9vuHlIUEcRLFo8/Xh3GtZCBnm181VgvOXIABKTVyTePA=="], @@ -1770,17 +1850,17 @@ "encoding-japanese": ["encoding-japanese@2.2.0", "", {}, "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A=="], - "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], "errx": ["errx@0.1.0", "", {}, "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q=="], - "es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], + "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], "es-array-method-boxes-properly": ["es-array-method-boxes-properly@1.0.0", "", {}, "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="], @@ -1800,9 +1880,49 @@ "es6-promise": ["es6-promise@4.2.8", "", {}, "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="], - "esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], + "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "esbuild-android-64": ["esbuild-android-64@0.14.54", "", { "os": "android", "cpu": "x64" }, "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ=="], + + "esbuild-android-arm64": ["esbuild-android-arm64@0.14.54", "", { "os": "android", "cpu": "arm64" }, "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg=="], + + "esbuild-darwin-64": ["esbuild-darwin-64@0.14.54", "", { "os": "darwin", "cpu": "x64" }, "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug=="], + + "esbuild-darwin-arm64": ["esbuild-darwin-arm64@0.14.54", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw=="], + + "esbuild-freebsd-64": ["esbuild-freebsd-64@0.14.54", "", { "os": "freebsd", "cpu": "x64" }, "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg=="], + + "esbuild-freebsd-arm64": ["esbuild-freebsd-arm64@0.14.54", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q=="], + + "esbuild-linux-32": ["esbuild-linux-32@0.14.54", "", { "os": "linux", "cpu": "ia32" }, "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw=="], + + "esbuild-linux-64": ["esbuild-linux-64@0.14.54", "", { "os": "linux", "cpu": "x64" }, "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg=="], + + "esbuild-linux-arm": ["esbuild-linux-arm@0.14.54", "", { "os": "linux", "cpu": "arm" }, "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw=="], + + "esbuild-linux-arm64": ["esbuild-linux-arm64@0.14.54", "", { "os": "linux", "cpu": "arm64" }, "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig=="], + + "esbuild-linux-mips64le": ["esbuild-linux-mips64le@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw=="], + + "esbuild-linux-ppc64le": ["esbuild-linux-ppc64le@0.14.54", "", { "os": "linux", "cpu": "ppc64" }, "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ=="], + + "esbuild-linux-riscv64": ["esbuild-linux-riscv64@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg=="], + + "esbuild-linux-s390x": ["esbuild-linux-s390x@0.14.54", "", { "os": "linux", "cpu": "s390x" }, "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA=="], + + "esbuild-netbsd-64": ["esbuild-netbsd-64@0.14.54", "", { "os": "none", "cpu": "x64" }, "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w=="], + + "esbuild-openbsd-64": ["esbuild-openbsd-64@0.14.54", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw=="], + + "esbuild-sunos-64": ["esbuild-sunos-64@0.14.54", "", { "os": "sunos", "cpu": "x64" }, "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw=="], + + "esbuild-windows-32": ["esbuild-windows-32@0.14.54", "", { "os": "win32", "cpu": "ia32" }, "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w=="], + + "esbuild-windows-64": ["esbuild-windows-64@0.14.54", "", { "os": "win32", "cpu": "x64" }, "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ=="], + + "esbuild-windows-arm64": ["esbuild-windows-arm64@0.14.54", "", { "os": "win32", "cpu": "arm64" }, "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg=="], + + "escalade": ["escalade@https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", {}], "escape-goat": ["escape-goat@3.0.0", "", {}, "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="], @@ -1818,25 +1938,25 @@ "eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="], - "eslint-config-prettier": ["eslint-config-prettier@10.1.2", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA=="], + "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], "eslint-config-standard": ["eslint-config-standard@17.1.0", "", { "peerDependencies": { "eslint": "^8.0.1", "eslint-plugin-import": "^2.25.2", "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", "eslint-plugin-promise": "^6.0.0" } }, "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q=="], "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], - "eslint-module-utils": ["eslint-module-utils@2.12.0", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg=="], + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], "eslint-plugin-es": ["eslint-plugin-es@3.0.1", "", { "dependencies": { "eslint-utils": "^2.0.0", "regexpp": "^3.0.0" }, "peerDependencies": { "eslint": ">=4.19.1" } }, "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ=="], "eslint-plugin-es-x": ["eslint-plugin-es-x@7.8.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", "@eslint-community/regexpp": "^4.11.0", "eslint-compat-utils": "^0.5.1" }, "peerDependencies": { "eslint": ">=8" } }, "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ=="], - "eslint-plugin-import": ["eslint-plugin-import@2.31.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.0", "hasown": "^2.0.2", "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.0", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A=="], + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], "eslint-plugin-n": ["eslint-plugin-n@16.6.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", "globals": "^13.24.0", "ignore": "^5.2.4", "is-builtin-module": "^3.2.1", "is-core-module": "^2.12.1", "minimatch": "^3.1.2", "resolve": "^1.22.2", "semver": "^7.5.3" }, "peerDependencies": { "eslint": ">=7.0.0" } }, "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ=="], "eslint-plugin-node": ["eslint-plugin-node@11.1.0", "", { "dependencies": { "eslint-plugin-es": "^3.0.0", "eslint-utils": "^2.0.0", "ignore": "^5.1.1", "minimatch": "^3.0.4", "resolve": "^1.10.1", "semver": "^6.1.0" }, "peerDependencies": { "eslint": ">=5.16.0" } }, "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g=="], - "eslint-plugin-prettier": ["eslint-plugin-prettier@5.4.0", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.0" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA=="], + "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.4", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg=="], "eslint-plugin-promise": ["eslint-plugin-promise@6.6.0", "", { "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ=="], @@ -1850,7 +1970,7 @@ "eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - "eslint-webpack-plugin": ["eslint-webpack-plugin@5.0.1", "", { "dependencies": { "@types/eslint": "^9.6.1", "jest-worker": "^29.7.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "schema-utils": "^4.3.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0", "webpack": "^5.0.0" } }, "sha512-Ur100Vi+z0uP7j4Z8Ccah0pXmNHhl3f7P2hCYZj3mZCOSc33G5c1R/vZ4KCapwWikPgRyD4dkangx6JW3KaVFQ=="], + "eslint-webpack-plugin": ["eslint-webpack-plugin@5.0.2", "", { "dependencies": { "@types/eslint": "^9.6.1", "flatted": "^3.3.3", "jest-worker": "^29.7.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "schema-utils": "^4.3.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0", "webpack": "^5.0.0" } }, "sha512-cB7EO2o+4gPUzK6zxgegSet8uu/hHwzOiG+2976MHWiwWFj9mmPbTrzlW0InFl6hl89S1D9MPKK5F7vNFpZc4g=="], "espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], @@ -1874,21 +1994,25 @@ "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "exit": ["exit@0.1.2", "", {}, "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ=="], + "exit-x": ["exit-x@0.2.2", "", {}, "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ=="], + "expect": ["expect@27.5.1", "", { "dependencies": { "@jest/types": "^27.5.1", "jest-get-type": "^27.5.1", "jest-matcher-utils": "^27.5.1", "jest-message-util": "^27.5.1" } }, "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw=="], - "expect-type": ["expect-type@1.2.1", "", {}, "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw=="], + "expect-type": ["expect-type@1.2.2", "", {}, "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA=="], "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], - "express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="], + "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], - "express-slow-down": ["express-slow-down@2.0.3", "", { "dependencies": { "express-rate-limit": "7" }, "peerDependencies": { "express": "4 || 5 || ^5.0.0-beta.1" } }, "sha512-vATCiFd8uQHtTeK5/Q0nLUukhZh+RV5zkcHxLQr0X5dEFVEYqzVXEe48nW23Z49fwtR+ApD9zn9sZRisTCR99w=="], + "express-slow-down": ["express-slow-down@2.1.0", "", { "dependencies": { "express-rate-limit": "7" }, "peerDependencies": { "express": "4 || 5 || ^5.0.0-beta.1" } }, "sha512-tQ/ItTDbGfo+fLS+jxu19vgYOgZk7wyOakuAsnzl8f7HmxG3ynWAoo136+oqB+rqHCk3QyM6VoXL03qA5a4gVQ=="], - "exsolve": ["exsolve@1.0.5", "", {}, "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg=="], + "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], "ext-list": ["ext-list@2.2.2", "", { "dependencies": { "mime-db": "^1.28.0" } }, "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA=="], @@ -1906,7 +2030,7 @@ "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], - "fast-equals": ["fast-equals@5.2.2", "", {}, "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw=="], + "fast-equals": ["fast-equals@5.3.2", "", {}, "sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ=="], "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], @@ -1918,7 +2042,7 @@ "fast-printf": ["fast-printf@1.6.10", "", {}, "sha512-GwTgG9O4FVIdShhbVF3JxOgSBY2+ePGsu2V/UONgoCPzF9VY6ZdBMKsHKCYQHZwNk3qNouUolRDsgVxcVA5G1w=="], - "fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], @@ -1926,13 +2050,15 @@ "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], - "fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "federation": ["federation@workspace:federation"], + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + "file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="], - "file-type": ["file-type@19.6.0", "", { "dependencies": { "get-stream": "^9.0.1", "strtok3": "^9.0.1", "token-types": "^6.0.0", "uint8array-extras": "^1.3.0" } }, "sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ=="], + "file-type": ["file-type@20.5.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.6", "strtok3": "^10.2.0", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg=="], "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], @@ -1958,13 +2084,13 @@ "flush-promises": ["flush-promises@1.0.2", "", {}, "sha512-G0sYfLQERwKz4+4iOZYQEZVpOt9zQrlItIxQAAYAWpfby3gbHrx0osCHz5RLl/XoXevXk0xoN4hDFky/VV9TrA=="], - "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "foreground-child": ["foreground-child@https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }], - "form-data": ["form-data@4.0.2", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" } }, "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w=="], + "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], @@ -1984,7 +2110,7 @@ "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "fsevents": ["fsevents@2.3.3", "", {}, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -1994,11 +2120,13 @@ "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "geojson": ["geojson@0.5.0", "", {}, "sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-caller-file": ["get-caller-file@https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", {}], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], @@ -2014,7 +2142,7 @@ "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], + "get-tsconfig": ["get-tsconfig@4.11.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-sNsqf7XKQ38IawiVGPOoAlqZo1DMrO7TU+ZcZwi7yLl7/7S0JwmoBMKz/IkUPhSoXM0Ng3vT0yB1iCe5XavDeQ=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], @@ -2064,7 +2192,7 @@ "graphql-type-json": ["graphql-type-json@0.3.2", "", { "peerDependencies": { "graphql": ">=0.8.0" } }, "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg=="], - "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + "handlebars": ["handlebars@https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" } }], "harmony-reflect": ["harmony-reflect@1.6.2", "", {}, "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g=="], @@ -2090,7 +2218,7 @@ "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], - "hookified": ["hookified@1.8.2", "", {}, "sha512-5nZbBNP44sFCDjSoB//0N7m508APCgbQ4mGGo1KJGBYyCKNHfry1Pvd0JVHZIxjdnqn8nFRBAN/eFB6Rk/4w5w=="], + "hookified": ["hookified@1.12.1", "", {}, "sha512-xnKGl+iMIlhrZmGHB729MqlmPoWBznctSQTYCpFKqNsCgimJQmithcW0xSQMMFzYnV2iKUh25alswn6epgxS0Q=="], "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], @@ -2104,7 +2232,7 @@ "htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="], - "http-cache-semantics": ["http-cache-semantics@4.1.1", "", {}, "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="], + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], @@ -2118,9 +2246,9 @@ "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], - "hypercore-crypto": ["hypercore-crypto@3.6.0", "", { "dependencies": { "b4a": "^1.6.6", "compact-encoding": "^2.15.0", "sodium-universal": "^5.0.0" } }, "sha512-0slkW1wzq4B95SD8Z5nt1Yf/3KrIcGsBWTJTsCjHzMXie+sZ5I2IkWcxX1mo4+c0xVESnKAKphKSpGf2kf2BGA=="], + "hypercore-crypto": ["hypercore-crypto@3.6.1", "", { "dependencies": { "b4a": "^1.6.6", "compact-encoding": "^2.15.0", "sodium-universal": "^5.0.0" } }, "sha512-ltIz2uDwy9pO/ZGTvqcjzyBkvt6O4cVm4r/nNxh0GFs/RbQtqP/i4wCvLEdmU7ptgtnw7fI67WYD1aHPuv4OVA=="], - "i18n": ["i18n@0.15.1", "", { "dependencies": { "@messageformat/core": "^3.0.0", "debug": "^4.3.3", "fast-printf": "^1.6.9", "make-plural": "^7.0.0", "math-interval-parser": "^2.0.1", "mustache": "^4.2.0" } }, "sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA=="], + "i18n": ["i18n@0.15.2", "", { "dependencies": { "@messageformat/core": "^3.4.0", "debug": "^4.4.3", "fast-printf": "^1.6.10", "make-plural": "^7.4.0", "math-interval-parser": "^2.0.1", "mustache": "^4.2.0" } }, "sha512-mdBxCfC651UL/hNizIQgB1NHwbBKjlrPcsoTzd/X8rNbJlS1FMF//TOyHEVFg9Dxo0RcrI2ZKt1AFTNe3Q40og=="], "i18n-locales": ["i18n-locales@0.0.5", "", { "dependencies": { "@ladjs/country-language": "^0.2.1" } }, "sha512-Kve1AHy6rqyfJHPy8MIvaKBKhHhHPXV+a/TgMkjp3UBhO3gfWR40ZQn8Xy7LI6g3FhmbvkFtv+GCZy6yvuyeHQ=="], @@ -2128,19 +2256,19 @@ "identity-obj-proxy": ["identity-obj-proxy@3.0.0", "", { "dependencies": { "harmony-reflect": "^1.4.6" } }, "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ieee754": ["ieee754@https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", {}], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "ignore-by-default": ["ignore-by-default@1.0.1", "", {}, "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="], - "immutable": ["immutable@5.1.2", "", {}, "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ=="], + "immutable": ["immutable@5.1.3", "", {}, "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg=="], - "import-cwd": ["import-cwd@3.0.0", "", { "dependencies": { "import-from": "^3.0.0" } }, "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg=="], + "import-cwd": ["import-cwd@https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", { "dependencies": { "import-from": "^3.0.0" } }], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "import-from": ["import-from@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ=="], + "import-from": ["import-from@https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", { "dependencies": { "resolve-from": "^5.0.0" } }], "import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="], @@ -2192,7 +2320,7 @@ "is-generator-fn": ["is-generator-fn@2.1.0", "", {}, "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="], - "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], @@ -2200,6 +2328,8 @@ "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], @@ -2244,7 +2374,7 @@ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isexe": ["isexe@https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", {}], "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], @@ -2254,13 +2384,13 @@ "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="], - "istanbul-reports": ["istanbul-reports@3.1.7", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g=="], + "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], "iterall": ["iterall@1.3.0", "", {}, "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "jackspeak": ["jackspeak@https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }], - "jake": ["jake@10.9.2", "", { "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", "filelist": "^1.0.4", "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" } }, "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA=="], + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], "jest": ["jest@27.2.4", "", { "dependencies": { "@jest/core": "^27.2.4", "import-local": "^3.0.2", "jest-cli": "^27.2.4" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": { "jest": "bin/jest.js" } }, "sha512-h4uqb1EQLfPulWyUFFWv9e9Nn8sCqsJ/j3wk/KCY0p4s4s0ICCfP3iMf6hRf5hEhsDyvyrCgKiZXma63gMz16A=="], @@ -2322,13 +2452,13 @@ "jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "joi": ["joi@17.13.3", "", { "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", "@sideway/address": "^4.1.5", "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } }, "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA=="], "joi-extract-type": ["joi-extract-type@15.0.8", "", { "dependencies": { "@hapi/joi": "~15", "@types/hapi__joi": "~15" } }, "sha512-Or97aW6QN6YJq0B+x/vYs65+nmcPvYDE7xhlwRl7yHzY+7Z8pVaj0zxjdJlXmIA9zRcbbYQKCGvW+I4g0kUHgA=="], - "jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + "jose": ["jose@https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", {}], "js-beautify": ["js-beautify@1.15.4", "", { "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", "glob": "^10.4.2", "js-cookie": "^3.0.5", "nopt": "^7.2.1" }, "bin": { "css-beautify": "js/bin/css-beautify.js", "html-beautify": "js/bin/html-beautify.js", "js-beautify": "js/bin/js-beautify.js" } }, "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA=="], @@ -2354,11 +2484,11 @@ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - "jsonc-eslint-parser": ["jsonc-eslint-parser@2.4.0", "", { "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", "espree": "^9.0.0", "semver": "^7.3.5" } }, "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg=="], + "jsonc-eslint-parser": ["jsonc-eslint-parser@2.4.1", "", { "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", "espree": "^9.0.0", "semver": "^7.3.5" } }, "sha512-uuPNLJkKN8NXAlZlQ6kmUF9qO+T6Kyd7oV4+/7yy8Jz6+MZNyhPq8EdLpdfnPVzUC8qSf1b4j1azKaGnFsjmsw=="], "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "jstransformer": ["jstransformer@1.0.0", "", { "dependencies": { "is-promise": "^2.0.0", "promise": "^7.0.1" } }, "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A=="], @@ -2380,7 +2510,7 @@ "knitwork": ["knitwork@1.2.0", "", {}, "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg=="], - "known-css-properties": ["known-css-properties@0.36.0", "", {}, "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA=="], + "known-css-properties": ["known-css-properties@0.37.0", "", {}, "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ=="], "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], @@ -2388,7 +2518,7 @@ "leaflet": ["leaflet@1.9.4", "", {}, "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="], - "leaflet-geosearch": ["leaflet-geosearch@4.2.0", "", { "optionalDependencies": { "@googlemaps/js-api-loader": "^1.16.6", "leaflet": "^1.6.0" } }, "sha512-UWNhFSaUcLlAP5UQY75ziWCl3cp0UCcmcFczPHLHjuAVPOHoPTe0nSgHJuI3pSTJBQm46NYoZOlgonrWceUznQ=="], + "leaflet-geosearch": ["leaflet-geosearch@4.2.2", "", { "optionalDependencies": { "@googlemaps/js-api-loader": "^1.16.6", "leaflet": "^1.6.0" } }, "sha512-847zdoX0SJcDCwPmbjO0C8ngPby14bYl7vfY4fLAKLi+AlIa2kWX2FXChu+kwzSQp45IF3buluS4YwbYITGkwA=="], "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], @@ -2396,33 +2526,35 @@ "libbase64": ["libbase64@1.3.0", "", {}, "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg=="], - "libmime": ["libmime@5.3.6", "", { "dependencies": { "encoding-japanese": "2.2.0", "iconv-lite": "0.6.3", "libbase64": "1.3.0", "libqp": "2.1.1" } }, "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA=="], + "libmime": ["libmime@5.3.7", "", { "dependencies": { "encoding-japanese": "2.2.0", "iconv-lite": "0.6.3", "libbase64": "1.3.0", "libqp": "2.1.1" } }, "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw=="], - "libphonenumber-js": ["libphonenumber-js@1.12.7", "", {}, "sha512-0nYZSNj/QEikyhcM5RZFXGlCB/mr4PVamnT1C2sKBnDDTYndrvbybYjvg+PMqAndQHlLbwQ3socolnL3WWTUFA=="], + "libphonenumber-js": ["libphonenumber-js@1.12.23", "", {}, "sha512-RN3q3gImZ91BvRDYjWp7ICz3gRn81mW5L4SW+2afzNCC0I/nkXstBgZThQGTE3S/9q5J90FH4dP+TXx8NhdZKg=="], "libqp": ["libqp@2.1.1", "", {}, "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow=="], - "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="], + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], @@ -2460,7 +2592,7 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "loupe": ["loupe@3.1.3", "", {}, "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug=="], + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], @@ -2468,13 +2600,13 @@ "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], - "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], - "mailparser": ["mailparser@3.7.2", "", { "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.6.3", "libmime": "5.3.6", "linkify-it": "5.0.0", "mailsplit": "5.4.2", "nodemailer": "6.9.16", "punycode.js": "2.3.1", "tlds": "1.255.0" } }, "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q=="], + "mailparser": ["mailparser@3.7.4", "", { "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.6.3", "libmime": "5.3.7", "linkify-it": "5.0.0", "mailsplit": "5.4.5", "nodemailer": "7.0.4", "punycode.js": "2.3.1", "tlds": "1.259.0" } }, "sha512-Beh4yyR4jLq3CZZ32asajByrXnW8dLyKCAQD3WvtTiBnMtFWhxO+wa93F6sJNjDmfjxXs4NRNjw3XAGLqZR3Vg=="], - "mailsplit": ["mailsplit@5.4.2", "", { "dependencies": { "libbase64": "1.3.0", "libmime": "5.3.6", "libqp": "2.1.1" } }, "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA=="], + "mailsplit": ["mailsplit@5.4.5", "", { "dependencies": { "libbase64": "1.3.0", "libmime": "5.3.7", "libqp": "2.1.1" } }, "sha512-oMfhmvclR689IIaQmIcR5nODnZRRVwAKtqFT407TIvmhX2OLUBnshUTcxzQBt3+96sZVDud9NfSe1NxAkUNXEQ=="], "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], @@ -2522,13 +2654,13 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "minipass": ["minipass@https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", {}], "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - "mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="], + "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], "mock-apollo-client": ["mock-apollo-client@1.3.1", "", { "peerDependencies": { "@apollo/client": "^3.0.0" } }, "sha512-jBl1YGofh9RpTUFfShwIumiry5qRkR1LYW12K1iZ576kMFh03psHTRiuY2k3dT6cUQ28RAK4gRFl9lVloazGhA=="], @@ -2552,6 +2684,8 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], + "nat-sampler": ["nat-sampler@1.0.1", "", {}, "sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -2572,9 +2706,9 @@ "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], - "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "node-fetch": ["node-fetch@https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", { "dependencies": { "whatwg-url": "^5.0.0" } }], - "node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], @@ -2582,9 +2716,9 @@ "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + "node-releases": ["node-releases@2.0.23", "", {}, "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg=="], - "nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], + "nodemailer": ["nodemailer@6.6.5", "", {}, "sha512-C/v856DBijUzHcHIgGpQoTrfsH3suKIRAGliIzCstatM2cAa+MYX3LuyCrABiO/cdJTxgBBHXxV1ztiqUwst5A=="], "nodemon": ["nodemon@2.0.22", "", { "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" } }, "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ=="], @@ -2598,15 +2732,15 @@ "normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="], - "normalize-url": ["normalize-url@8.0.1", "", {}, "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w=="], + "normalize-url": ["normalize-url@8.1.0", "", {}, "sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w=="], "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - "nwsapi": ["nwsapi@2.2.20", "", {}, "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA=="], + "nwsapi": ["nwsapi@2.2.22", "", {}, "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ=="], - "nypm": ["nypm@0.6.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^2.0.0", "tinyexec": "^0.3.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg=="], + "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -2626,7 +2760,7 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -2636,7 +2770,7 @@ "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], - "openai": ["openai@4.97.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-LRoiy0zvEf819ZUEJhgfV8PfsE8G5WpQi4AwA1uCV8SKvvtXQkoWUFkepD6plqyJQRghy2+AEPQ07FrJFKHZ9Q=="], + "openai": ["openai@4.104.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA=="], "optimism": ["optimism@0.18.1", "", { "dependencies": { "@wry/caches": "^1.0.0", "@wry/context": "^0.7.0", "@wry/trie": "^0.5.0", "tslib": "^2.3.0" } }, "sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ=="], @@ -2662,7 +2796,7 @@ "p-wait-for": ["p-wait-for@3.2.0", "", { "dependencies": { "p-timeout": "^3.0.0" } }, "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA=="], - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "package-json-from-dist": ["package-json-from-dist@https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", {}], "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], @@ -2670,7 +2804,7 @@ "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - "parse-github-url": ["parse-github-url@1.0.3", "", { "bin": { "parse-github-url": "cli.js" } }, "sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww=="], + "parse-github-url": ["parse-github-url@https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.3.tgz", {}], "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], @@ -2688,11 +2822,11 @@ "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-key": ["path-key@https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", {}], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "path-scurry": ["path-scurry@https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }], "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], @@ -2700,15 +2834,13 @@ "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], - "pathval": ["pathval@2.0.0", "", {}, "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA=="], + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], "peberminta": ["peberminta@0.9.0", "", {}, "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="], - "peek-readable": ["peek-readable@5.4.2", "", {}, "sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg=="], - "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], - "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], + "perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -2716,7 +2848,7 @@ "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], - "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + "pirates": ["pirates@https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", {}], "piscina": ["piscina@4.9.2", "", { "optionalDependencies": { "@napi-rs/nice": "^1.0.1" } }, "sha512-Fq0FERJWFEUpB4eSY59wSNwXD4RYqR+nR/WiEVcZW8IWfVBxJJafcgTEZDQo8k3w0sUarJ8RyVbbUF4GQ2LGbQ=="], @@ -2728,7 +2860,7 @@ "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "postcss-html": ["postcss-html@1.8.0", "", { "dependencies": { "htmlparser2": "^8.0.0", "js-tokens": "^9.0.0", "postcss": "^8.5.0", "postcss-safe-parser": "^6.0.0" } }, "sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ=="], @@ -2746,7 +2878,7 @@ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="], @@ -2800,15 +2932,19 @@ "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], + "pure-rand": ["pure-rand@7.0.1", "", {}, "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ=="], + + "qified": ["qified@0.5.0", "", { "dependencies": { "hookified": "^1.12.1" } }, "sha512-Zj6Q/Vc/SQ+Fzc87N90jJUzBzxD7MVQ2ZvGyMmYtnl2u1a07CejAhvtk4ZwASos+SiHKCAIylyGHJKIek75QBw=="], + "qrcanvas": ["qrcanvas@3.1.2", "", { "dependencies": { "@babel/runtime": "^7.11.2", "qrcode-generator": "^1.4.4" } }, "sha512-lNcAyCHN0Eno/mJ5eBc7lHV/5ejAJxII0UELthG3bNnlLR+u8hCc7CR+hXBawbYUf96kNIosXfG2cJzx92ZWKg=="], "qrcanvas-vue": ["qrcanvas-vue@3.0.0", "", { "dependencies": { "@babel/runtime": "^7.16.0", "qrcanvas": "^3.1.2" }, "peerDependencies": { "vue": "3.x" } }, "sha512-B7LgAyOEJWf8Bz0y2J8M0OXE77uNWcH7PWr6q8ihyuQE5NP9zopY9wJGTZIT6Mu7oEOczPHMLDedZqFCT2Qxdw=="], - "qrcode-generator": ["qrcode-generator@1.4.4", "", {}, "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw=="], + "qrcode-generator": ["qrcode-generator@1.5.2", "", {}, "sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw=="], "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - "quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="], + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="], @@ -2856,7 +2992,7 @@ "require-addon": ["require-addon@1.1.0", "", { "dependencies": { "bare-addon-resolve": "^1.3.0", "bare-url": "^2.1.0" } }, "sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg=="], - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-directory": ["require-directory@https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", {}], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], @@ -2888,7 +3024,7 @@ "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "rollup": ["rollup@4.40.2", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.2", "@rollup/rollup-android-arm64": "4.40.2", "@rollup/rollup-darwin-arm64": "4.40.2", "@rollup/rollup-darwin-x64": "4.40.2", "@rollup/rollup-freebsd-arm64": "4.40.2", "@rollup/rollup-freebsd-x64": "4.40.2", "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", "@rollup/rollup-linux-arm-musleabihf": "4.40.2", "@rollup/rollup-linux-arm64-gnu": "4.40.2", "@rollup/rollup-linux-arm64-musl": "4.40.2", "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-musl": "4.40.2", "@rollup/rollup-linux-s390x-gnu": "4.40.2", "@rollup/rollup-linux-x64-gnu": "4.40.2", "@rollup/rollup-linux-x64-musl": "4.40.2", "@rollup/rollup-win32-arm64-msvc": "4.40.2", "@rollup/rollup-win32-ia32-msvc": "4.40.2", "@rollup/rollup-win32-x64-msvc": "4.40.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg=="], + "rollup": ["rollup@4.52.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.4", "@rollup/rollup-android-arm64": "4.52.4", "@rollup/rollup-darwin-arm64": "4.52.4", "@rollup/rollup-darwin-x64": "4.52.4", "@rollup/rollup-freebsd-arm64": "4.52.4", "@rollup/rollup-freebsd-x64": "4.52.4", "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", "@rollup/rollup-linux-arm-musleabihf": "4.52.4", "@rollup/rollup-linux-arm64-gnu": "4.52.4", "@rollup/rollup-linux-arm64-musl": "4.52.4", "@rollup/rollup-linux-loong64-gnu": "4.52.4", "@rollup/rollup-linux-ppc64-gnu": "4.52.4", "@rollup/rollup-linux-riscv64-gnu": "4.52.4", "@rollup/rollup-linux-riscv64-musl": "4.52.4", "@rollup/rollup-linux-s390x-gnu": "4.52.4", "@rollup/rollup-linux-x64-gnu": "4.52.4", "@rollup/rollup-linux-x64-musl": "4.52.4", "@rollup/rollup-openharmony-arm64": "4.52.4", "@rollup/rollup-win32-arm64-msvc": "4.52.4", "@rollup/rollup-win32-ia32-msvc": "4.52.4", "@rollup/rollup-win32-x64-gnu": "4.52.4", "@rollup/rollup-win32-x64-msvc": "4.52.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ=="], "rrweb-cssom": ["rrweb-cssom@0.7.1", "", {}, "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg=="], @@ -2912,11 +3048,11 @@ "safety-catch": ["safety-catch@1.0.2", "", {}, "sha512-C1UYVZ4dtbBxEtvOcpjBaaD27nP8MlvyAQEp2fOTOEe6pfUpk1cDUxij6BR1jZup6rSyUTaBBplK7LanskrULA=="], - "sass": ["sass@1.87.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw=="], + "sass": ["sass@1.93.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg=="], "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], - "schema-utils": ["schema-utils@4.3.2", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ=="], + "schema-utils": ["schema-utils@4.3.3", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA=="], "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], @@ -2924,7 +3060,7 @@ "selderee": ["selderee@0.6.0", "", { "dependencies": { "parseley": "^0.7.0" } }, "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg=="], - "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + "semver": ["semver@https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", {}], "semver-regex": ["semver-regex@4.0.5", "", {}, "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw=="], @@ -2948,15 +3084,15 @@ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], - "sha.js": ["sha.js@2.4.11", "", { "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" }, "bin": { "sha.js": "./bin.js" } }, "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ=="], + "sha.js": ["sha.js@https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", { "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }], "shared": ["shared@workspace:shared"], - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + "shebang-command": ["shebang-command@https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", { "dependencies": { "shebang-regex": "^3.0.0" } }], - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "shebang-regex": ["shebang-regex@https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", {}], - "shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="], + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], "shvl": ["shvl@2.0.3", "", {}, "sha512-V7C6S9Hlol6SzOJPnQ7qzOVEWUQImt3BNmmzh40wObhla3XOYMe4gGiYzLrJd5TFa+cI2f9LKIRJTTKZSTbWgw=="], @@ -2992,7 +3128,7 @@ "sort-keys-length": ["sort-keys-length@1.0.1", "", { "dependencies": { "sort-keys": "^1.0.0" } }, "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw=="], - "source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -3002,7 +3138,7 @@ "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], - "sql-highlight": ["sql-highlight@6.0.0", "", {}, "sha512-+fLpbAbWkQ+d0JEchJT/NrRRXbYRNbG15gFpANx73EwxQB1PRjj+k/OI0GTU0J63g8ikGkJECQp9z8XEJZvPRw=="], + "sql-highlight": ["sql-highlight@https://registry.npmjs.org/sql-highlight/-/sql-highlight-6.0.0.tgz", {}], "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], @@ -3014,17 +3150,19 @@ "std-env": ["std-env@3.9.0", "", {}, "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw=="], + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + "streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="], "streamsearch": ["streamsearch@0.1.2", "", {}, "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA=="], - "streamx": ["streamx@2.22.0", "", { "dependencies": { "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw=="], + "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], "string-length": ["string-length@4.0.2", "", { "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" } }, "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "string-width-cjs": ["string-width@https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }], "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], @@ -3036,7 +3174,7 @@ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi-cjs": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], @@ -3048,25 +3186,25 @@ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="], + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "strtok3": ["strtok3@9.1.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^5.3.1" } }, "sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw=="], + "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], - "stylelint": ["stylelint@16.19.1", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "@csstools/media-query-list-parser": "^4.0.2", "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", "css-tree": "^3.1.0", "debug": "^4.3.7", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^10.0.8", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", "ignore": "^7.0.3", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.36.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.5.3", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "supports-hyperlinks": "^3.2.0", "svg-tags": "^1.0.0", "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" } }, "sha512-C1SlPZNMKl+d/C867ZdCRthrS+6KuZ3AoGW113RZCOL0M8xOGpgx7G70wq7lFvqvm4dcfdGFVLB/mNaLFChRKw=="], + "stylelint": ["stylelint@16.25.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3", "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.2.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", "css-tree": "^3.1.0", "debug": "^4.4.3", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^10.1.4", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", "ignore": "^7.0.5", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.37.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.5.6", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "supports-hyperlinks": "^3.2.0", "svg-tags": "^1.0.0", "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" } }, "sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ=="], "stylelint-config-html": ["stylelint-config-html@1.1.0", "", { "peerDependencies": { "postcss-html": "^1.0.0", "stylelint": ">=14.0.0" } }, "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ=="], - "stylelint-config-recommended": ["stylelint-config-recommended@16.0.0", "", { "peerDependencies": { "stylelint": "^16.16.0" } }, "sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA=="], + "stylelint-config-recommended": ["stylelint-config-recommended@17.0.0", "", { "peerDependencies": { "stylelint": "^16.23.0" } }, "sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA=="], "stylelint-config-recommended-scss": ["stylelint-config-recommended-scss@14.1.0", "", { "dependencies": { "postcss-scss": "^4.0.9", "stylelint-config-recommended": "^14.0.1", "stylelint-scss": "^6.4.0" }, "peerDependencies": { "postcss": "^8.3.3", "stylelint": "^16.6.1" }, "optionalPeers": ["postcss"] }, "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg=="], - "stylelint-config-recommended-vue": ["stylelint-config-recommended-vue@1.6.0", "", { "dependencies": { "semver": "^7.3.5", "stylelint-config-html": ">=1.0.0", "stylelint-config-recommended": ">=6.0.0" }, "peerDependencies": { "postcss-html": "^1.0.0", "stylelint": ">=14.0.0" } }, "sha512-syk1adIHvbH2T1OiR/spUK4oQy35PZIDw8Zmc7E0+eVK9Z9SK3tdMpGRT/bgGnAPpMt/WaL9K1u0tlF6xM0sMQ=="], + "stylelint-config-recommended-vue": ["stylelint-config-recommended-vue@1.6.1", "", { "dependencies": { "semver": "^7.3.5", "stylelint-config-html": ">=1.0.0", "stylelint-config-recommended": ">=6.0.0" }, "peerDependencies": { "postcss-html": "^1.0.0", "stylelint": ">=14.0.0" } }, "sha512-lLW7hTIMBiTfjenGuDq2kyHA6fBWd/+Df7MO4/AWOxiFeXP9clbpKgg27kHfwA3H7UNMGC7aeP3mNlZB5LMmEQ=="], "stylelint-config-standard": ["stylelint-config-standard@36.0.1", "", { "dependencies": { "stylelint-config-recommended": "^14.0.1" }, "peerDependencies": { "stylelint": "^16.1.0" } }, "sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw=="], "stylelint-config-standard-scss": ["stylelint-config-standard-scss@14.0.0", "", { "dependencies": { "stylelint-config-recommended-scss": "^14.1.0", "stylelint-config-standard": "^36.0.1" }, "peerDependencies": { "postcss": "^8.3.3", "stylelint": "^16.11.0" }, "optionalPeers": ["postcss"] }, "sha512-6Pa26D9mHyi4LauJ83ls3ELqCglU6VfCXchovbEqQUiEkezvKdv6VgsIoMy58i00c854wVmOw0k8W5FTpuaVqg=="], - "stylelint-scss": ["stylelint-scss@6.12.0", "", { "dependencies": { "css-tree": "^3.0.1", "is-plain-object": "^5.0.0", "known-css-properties": "^0.36.0", "mdn-data": "^2.21.0", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.6", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "stylelint": "^16.0.2" } }, "sha512-U7CKhi1YNkM1pXUXl/GMUXi8xKdhl4Ayxdyceie1nZ1XNIdaUgMV6OArpooWcDzEggwgYD0HP/xIgVJo9a655w=="], + "stylelint-scss": ["stylelint-scss@6.12.1", "", { "dependencies": { "css-tree": "^3.0.1", "is-plain-object": "^5.0.0", "known-css-properties": "^0.36.0", "mdn-data": "^2.21.0", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.6", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "stylelint": "^16.0.2" } }, "sha512-UJUfBFIvXfly8WKIgmqfmkGKPilKB4L5j38JfsDd+OCg2GBdU0vGUV08Uw82tsRZzd4TbsUURVVNGeOhJVF7pA=="], "subscriptions-transport-ws": ["subscriptions-transport-ws@0.9.19", "", { "dependencies": { "backo2": "^1.0.2", "eventemitter3": "^3.1.0", "iterall": "^1.2.1", "symbol-observable": "^1.0.4", "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" }, "peerDependencies": { "graphql": ">=0.10.0" } }, "sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw=="], @@ -3084,17 +3222,17 @@ "symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="], - "synckit": ["synckit@0.11.4", "", { "dependencies": { "@pkgr/core": "^0.2.3", "tslib": "^2.8.1" } }, "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ=="], + "synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="], "table": ["table@6.9.0", "", { "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1" } }, "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A=="], - "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], "terminal-link": ["terminal-link@2.1.1", "", { "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" } }, "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ=="], - "terser": ["terser@5.39.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw=="], + "terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="], "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], @@ -3122,9 +3260,9 @@ "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - "tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "tinypool": ["tinypool@1.0.2", "", {}, "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA=="], + "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], "tinyrainbow": ["tinyrainbow@1.2.0", "", {}, "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ=="], @@ -3132,7 +3270,7 @@ "titleize": ["titleize@2.1.0", "", {}, "sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g=="], - "tlds": ["tlds@1.258.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-XGhStWuOlBA5D8QnyN2xtgB2cUOdJ3ztisne1DYVWMcVH29qh8eQIpRmP3HnuJLdgyzG0HpdGzRMu1lm/Oictw=="], + "tlds": ["tlds@1.260.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ=="], "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], @@ -3140,13 +3278,15 @@ "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], + "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], "token-stream": ["token-stream@1.0.0", "", {}, "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="], - "token-types": ["token-types@6.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="], + "token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="], "toposort": ["toposort@2.0.2", "", {}, "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="], @@ -3174,25 +3314,25 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsx": ["tsx@4.20.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ=="], + "tsx": ["tsx@4.20.6", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg=="], "tua-body-scroll-lock": ["tua-body-scroll-lock@1.5.3", "", {}, "sha512-44W12iqek41kZuTdpEUt3JTUsMx0IxfTajXWfQyMLgzsPaMYUPZLcJkwa4P0x24h5DQ3lYvDuYvphBo4+L0t4w=="], "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], - "turbo": ["turbo@2.5.2", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.2", "turbo-darwin-arm64": "2.5.2", "turbo-linux-64": "2.5.2", "turbo-linux-arm64": "2.5.2", "turbo-windows-64": "2.5.2", "turbo-windows-arm64": "2.5.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-Qo5lfuStr6LQh3sPQl7kIi243bGU4aHGDQJUf6ylAdGwks30jJFloc9NYHP7Y373+gGU9OS0faA4Mb5Sy8X9Xw=="], + "turbo": ["turbo@https://registry.npmjs.org/turbo/-/turbo-2.5.2.tgz", { "optionalDependencies": { "turbo-darwin-64": "2.5.2", "turbo-darwin-arm64": "2.5.2", "turbo-linux-64": "2.5.2", "turbo-linux-arm64": "2.5.2", "turbo-windows-64": "2.5.2", "turbo-windows-arm64": "2.5.2" } }], - "turbo-darwin-64": ["turbo-darwin-64@2.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-2aIl0Sx230nLk+Cg2qSVxvPOBWCZpwKNuAMKoROTvWKif6VMpkWWiR9XEPoz7sHeLmCOed4GYGMjL1bqAiIS/g=="], + "turbo-darwin-64": ["turbo-darwin-64@2.5.2", "", {}, "sha512-2aIl0Sx230nLk+Cg2qSVxvPOBWCZpwKNuAMKoROTvWKif6VMpkWWiR9XEPoz7sHeLmCOed4GYGMjL1bqAiIS/g=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MrFYhK/jYu8N6QlqZtqSHi3e4QVxlzqU3ANHTKn3/tThuwTLbNHEvzBPWSj5W7nZcM58dCqi6gYrfRz6bJZyAA=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.2", "", {}, "sha512-MrFYhK/jYu8N6QlqZtqSHi3e4QVxlzqU3ANHTKn3/tThuwTLbNHEvzBPWSj5W7nZcM58dCqi6gYrfRz6bJZyAA=="], - "turbo-linux-64": ["turbo-linux-64@2.5.2", "", { "os": "linux", "cpu": "x64" }, "sha512-LxNqUE2HmAJQ/8deoLgMUDzKxd5bKxqH0UBogWa+DF+JcXhtze3UTMr6lEr0dEofdsEUYK1zg8FRjglmwlN5YA=="], + "turbo-linux-64": ["turbo-linux-64@2.5.2", "", {}, "sha512-LxNqUE2HmAJQ/8deoLgMUDzKxd5bKxqH0UBogWa+DF+JcXhtze3UTMr6lEr0dEofdsEUYK1zg8FRjglmwlN5YA=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.5.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-0MI1Ao1q8zhd+UUbIEsrM+yLq1BsrcJQRGZkxIsHFlGp7WQQH1oR3laBgfnUCNdCotCMD6w4moc9pUbXdOR3bg=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.5.2", "", {}, "sha512-0MI1Ao1q8zhd+UUbIEsrM+yLq1BsrcJQRGZkxIsHFlGp7WQQH1oR3laBgfnUCNdCotCMD6w4moc9pUbXdOR3bg=="], - "turbo-windows-64": ["turbo-windows-64@2.5.2", "", { "os": "win32", "cpu": "x64" }, "sha512-hOLcbgZzE5ttACHHyc1ajmWYq4zKT42IC3G6XqgiXxMbS+4eyVYTL+7UvCZBd3Kca1u4TLQdLQjeO76zyDJc2A=="], + "turbo-windows-64": ["turbo-windows-64@https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.5.2.tgz", {}], - "turbo-windows-arm64": ["turbo-windows-arm64@2.5.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-fMU41ABhSLa18H8V3Z7BMCGynQ8x+wj9WyBMvWm1jeyRKgkvUYJsO2vkIsy8m0vrwnIeVXKOIn6eSe1ddlBVqw=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.5.2", "", {}, "sha512-fMU41ABhSLa18H8V3Z7BMCGynQ8x+wj9WyBMvWm1jeyRKgkvUYJsO2vkIsy8m0vrwnIeVXKOIn6eSe1ddlBVqw=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], @@ -3216,21 +3356,21 @@ "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], - "typeorm": ["typeorm@0.3.25", "", { "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "dayjs": "^1.11.13", "debug": "^4.4.0", "dedent": "^1.6.0", "dotenv": "^16.4.7", "glob": "^10.4.5", "sha.js": "^2.4.11", "sql-highlight": "^6.0.0", "tslib": "^2.8.1", "uuid": "^11.1.0", "yargs": "^17.7.2" }, "peerDependencies": { "@google-cloud/spanner": "^5.18.0 || ^6.0.0 || ^7.0.0", "@sap/hana-client": "^2.12.25", "better-sqlite3": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", "mongodb": "^5.8.0 || ^6.0.0", "mssql": "^9.1.1 || ^10.0.1 || ^11.0.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^6.3.0", "pg": "^8.5.1", "pg-native": "^3.0.0", "pg-query-stream": "^4.0.0", "redis": "^3.1.1 || ^4.0.0", "reflect-metadata": "^0.1.14 || ^0.2.0", "sql.js": "^1.4.0", "sqlite3": "^5.0.3", "ts-node": "^10.7.0", "typeorm-aurora-data-api-driver": "^2.0.0 || ^3.0.0" }, "optionalPeers": ["@google-cloud/spanner", "@sap/hana-client", "better-sqlite3", "hdb-pool", "ioredis", "mongodb", "mssql", "mysql2", "oracledb", "pg", "pg-native", "pg-query-stream", "redis", "sql.js", "sqlite3", "ts-node", "typeorm-aurora-data-api-driver"], "bin": { "typeorm": "cli.js", "typeorm-ts-node-esm": "cli-ts-node-esm.js", "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js" } }, "sha512-fTKDFzWXKwAaBdEMU4k661seZewbNYET4r1J/z3Jwf+eAvlzMVpTLKAVcAzg75WwQk7GDmtsmkZ5MfkmXCiFWg=="], + "typeorm": ["typeorm@0.3.25", "", { "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "dayjs": "^1.11.13", "debug": "^4.4.0", "dedent": "^1.6.0", "dotenv": "^16.4.7", "glob": "^10.4.5", "sha.js": "^2.4.11", "sql-highlight": "^6.0.0", "tslib": "^2.8.1", "uuid": "^11.1.0", "yargs": "^17.7.2" } }, "sha512-fTKDFzWXKwAaBdEMU4k661seZewbNYET4r1J/z3Jwf+eAvlzMVpTLKAVcAzg75WwQk7GDmtsmkZ5MfkmXCiFWg=="], "typescript": ["typescript@4.9.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="], "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - "udx-native": ["udx-native@1.17.8", "", { "dependencies": { "b4a": "^1.5.0", "bare-events": "^2.2.0", "require-addon": "^1.1.0", "streamx": "^2.14.0" } }, "sha512-nB5SxTF9WzTNrxJnVSyEOtapoPjxAU1KboN/z1JWMtAVXArwtQ9Mxn+jJvlx4skINQHH6xUqQsQdSCL1Ja2h1Q=="], + "udx-native": ["udx-native@1.18.3", "", { "dependencies": { "b4a": "^1.5.0", "bare-events": "^2.2.0", "require-addon": "^1.1.0", "streamx": "^2.22.0" } }, "sha512-GqYA64plvp8+LY20PQvWuS2wY6/UBKLwpWb/po0iPlEYYnyxAqdag1yKeNJJ+HZtV95T4VYxKbT1xV8eV4iTiw=="], "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], - "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + "uglify-js": ["uglify-js@https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", {}], "uint-rng": ["uint-rng@1.2.1", "", { "dependencies": { "tiny-webcrypto": "^1.0.2" } }, "sha512-swhDg5H+3DX2sIvnYA7VMBMXV/t8mPxvh49CjCDkwFmj/3OZIDOQwJANBgM1MPSUBrUHNIlXmU7/GcL7m4907g=="], - "uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], @@ -3246,7 +3386,7 @@ "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], - "unimport": ["unimport@5.0.1", "", { "dependencies": { "acorn": "^8.14.1", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.1", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.3", "picomatch": "^4.0.2", "pkg-types": "^2.1.0", "scule": "^1.3.0", "strip-literal": "^3.0.0", "tinyglobby": "^0.2.13", "unplugin": "^2.3.2", "unplugin-utils": "^0.2.4" } }, "sha512-1YWzPj6wYhtwHE+9LxRlyqP4DiRrhGfJxdtH475im8ktyZXO3jHj/3PZ97zDdvkYoovFdi0K4SKl3a7l92v3sQ=="], + "unimport": ["unimport@5.4.1", "", { "dependencies": { "acorn": "^8.15.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.19", "mlly": "^1.8.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "pkg-types": "^2.3.0", "scule": "^1.3.0", "strip-literal": "^3.1.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.10", "unplugin-utils": "^0.3.0" } }, "sha512-wMZ2JKUCleCK2zfRHeWcbrUHKXOC3SVBYkyn/wTGzh0THX6sT4hSjuKXxKANN4/WMbT6ZPM4JzcDcnhD2x9Bpg=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -3256,10 +3396,12 @@ "unplugin-icons": ["unplugin-icons@0.19.3", "", { "dependencies": { "@antfu/install-pkg": "^0.4.1", "@antfu/utils": "^0.7.10", "@iconify/utils": "^2.1.29", "debug": "^4.3.6", "kolorist": "^1.8.0", "local-pkg": "^0.5.0", "unplugin": "^1.12.0" }, "peerDependencies": { "@svgr/core": ">=7.0.0", "@svgx/core": "^1.0.1", "@vue/compiler-sfc": "^3.0.2 || ^2.7.0", "vue-template-compiler": "^2.6.12", "vue-template-es2015-compiler": "^1.9.0" }, "optionalPeers": ["@svgr/core", "@svgx/core", "@vue/compiler-sfc", "vue-template-compiler", "vue-template-es2015-compiler"] }, "sha512-EUegRmsAI6+rrYr0vXjFlIP+lg4fSC4zb62zAZKx8FGXlWAGgEGBCa3JDe27aRAXhistObLPbBPhwa/0jYLFkQ=="], - "unplugin-utils": ["unplugin-utils@0.2.4", "", { "dependencies": { "pathe": "^2.0.2", "picomatch": "^4.0.2" } }, "sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA=="], + "unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="], "unplugin-vue-components": ["unplugin-vue-components@0.27.5", "", { "dependencies": { "@antfu/utils": "^0.7.10", "@rollup/pluginutils": "^5.1.3", "chokidar": "^3.6.0", "debug": "^4.3.7", "fast-glob": "^3.3.2", "local-pkg": "^0.5.1", "magic-string": "^0.30.14", "minimatch": "^9.0.5", "mlly": "^1.7.3", "unplugin": "^1.16.0" }, "peerDependencies": { "@babel/parser": "^7.15.8", "@nuxt/kit": "^3.2.2", "vue": "2 || 3" }, "optionalPeers": ["@babel/parser", "@nuxt/kit"] }, "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg=="], + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], + "unslab": ["unslab@1.3.0", "", { "dependencies": { "b4a": "^1.6.6" } }, "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ=="], "untyped": ["untyped@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "defu": "^6.1.4", "jiti": "^2.4.2", "knitwork": "^1.2.0", "scule": "^1.3.0" }, "bin": { "untyped": "dist/cli.mjs" } }, "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g=="], @@ -3276,7 +3418,7 @@ "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "uuid": ["uuid@https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", {}], "v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="], @@ -3284,13 +3426,13 @@ "valid-data-url": ["valid-data-url@3.0.1", "", {}, "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA=="], - "validator": ["validator@13.15.0", "", {}, "sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA=="], + "validator": ["validator@13.15.15", "", {}, "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - "vee-validate": ["vee-validate@4.15.0", "", { "dependencies": { "@vue/devtools-api": "^7.5.2", "type-fest": "^4.8.3" }, "peerDependencies": { "vue": "^3.4.26" } }, "sha512-PGJh1QCFwCBjbHu5aN6vB8macYVWrajbDvgo1Y/8fz9n/RVIkLmZCJDpUgu7+mUmCOPMxeyq7vXUOhbwAqdXcA=="], + "vee-validate": ["vee-validate@4.15.1", "", { "dependencies": { "@vue/devtools-api": "^7.5.2", "type-fest": "^4.8.3" }, "peerDependencies": { "vue": "^3.4.26" } }, "sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg=="], - "vite": ["vite@5.4.19", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA=="], + "vite": ["vite@5.4.20", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g=="], "vite-node": ["vite-node@2.1.9", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA=="], @@ -3314,7 +3456,7 @@ "vue-apollo": ["vue-apollo@3.1.2", "", { "dependencies": { "chalk": "^2.4.2", "serialize-javascript": "^4.0.0", "throttle-debounce": "^2.1.0" }, "peerDependencies": { "graphql-tag": "^2" } }, "sha512-ZS4b9C+iiiVmjpbTcxp2ryrRiX4lux+duPuyj4qm25hS8Y45NjQXitgLYitSToqepl52/VZDrRnD07G2RpbejQ=="], - "vue-component-type-helpers": ["vue-component-type-helpers@2.2.10", "", {}, "sha512-iDUO7uQK+Sab2tYuiP9D1oLujCWlhHELHMgV/cB13cuGbG4qwkLHvtfWb6FzvxrIOPDnU0oHsz2MlQjhYDeaHA=="], + "vue-component-type-helpers": ["vue-component-type-helpers@2.2.12", "", {}, "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw=="], "vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="], @@ -3340,7 +3482,7 @@ "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], - "watchpack": ["watchpack@2.4.2", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw=="], + "watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="], "web-resource-inliner": ["web-resource-inliner@6.0.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", "htmlparser2": "^5.0.0", "mime": "^2.4.6", "node-fetch": "^2.6.0", "valid-data-url": "^3.0.0" } }, "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A=="], @@ -3348,9 +3490,9 @@ "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], - "webpack": ["webpack@5.99.7", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w=="], + "webpack": ["webpack@5.102.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.5", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.2", "tapable": "^2.2.3", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.4", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-hUtqAR3ZLVEYDEABdBioQCIqSoguHbFn1K7WlPPWSuXmx0031BD73PSE35jKyftdSh4YLDoQNgK4pqBt5Q82MA=="], - "webpack-sources": ["webpack-sources@3.2.3", "", {}, "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="], + "webpack-sources": ["webpack-sources@3.3.3", "", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], @@ -3360,7 +3502,7 @@ "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which": ["which@https://registry.npmjs.org/which/-/which-2.0.2.tgz", { "dependencies": { "isexe": "^2.0.0" } }], "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], @@ -3370,7 +3512,7 @@ "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], - "which-runtime": ["which-runtime@1.2.1", "", {}, "sha512-8feIHccQFH/whiA1fD1b4c5+Q7T4ry1g1oHYc2mHnFh81tTQFsCvy3zhS2geUapkFAVBddUT/AM1a3rbqJweFg=="], + "which-runtime": ["which-runtime@1.3.2", "", {}, "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw=="], "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], @@ -3382,19 +3524,19 @@ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + "wordwrap": ["wordwrap@https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", {}], - "workerpool": ["workerpool@9.2.0", "", {}, "sha512-PKZqBOCo6CYkVOwAxWxQaSF2Fvb5Iv2fCeTP7buyWI2GiynWr46NcXSgK/idoV6e60dgCBfgYc+Un3HMvmqP8w=="], + "workerpool": ["workerpool@9.3.4", "", {}, "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg=="], - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi": ["wrap-ansi@https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }], - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi-cjs": ["wrap-ansi@https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - "ws": ["ws@8.18.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="], + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], "xache": ["xache@1.2.1", "", {}, "sha512-igRS6jPreJ54ABdzhh4mCDXcz+XMaWO2q1ABRV2yWYuk29jlp8VT7UBdCqNkX7rpYBbXsebVVKkwIuYZjyZNqA=="], @@ -3406,7 +3548,7 @@ "xss": ["xss@1.0.15", "", { "dependencies": { "commander": "^2.20.3", "cssfilter": "0.0.10" }, "bin": { "xss": "bin/xss" } }, "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg=="], - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "y18n": ["y18n@https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", {}], "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -3414,7 +3556,7 @@ "yaml-eslint-parser": ["yaml-eslint-parser@0.5.0", "", { "dependencies": { "eslint-visitor-keys": "^3.0.0", "lodash": "^4.17.21", "yaml": "^1.10.2" } }, "sha512-nJeyLA3YHAzhBTZbRAbu3W6xrSCucyxExmA+ZDtEdUFpGllxAZpto2Zxo2IG0r0eiuEiBM4e+wiAdxTziTq94g=="], - "yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "yargs": ["yargs@https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", { "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" } }], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], @@ -3426,13 +3568,15 @@ "yoctocolors-cjs": ["yoctocolors-cjs@2.1.2", "", {}, "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA=="], - "yup": ["yup@1.6.1", "", { "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", "toposort": "^2.0.2", "type-fest": "^2.19.0" } }, "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA=="], + "yup": ["yup@1.7.1", "", { "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", "toposort": "^2.0.2", "type-fest": "^2.19.0" } }, "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw=="], "zen-observable": ["zen-observable@0.8.15", "", {}, "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="], "zen-observable-ts": ["zen-observable-ts@1.2.5", "", { "dependencies": { "zen-observable": "0.8.15" } }, "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg=="], - "zod": ["zod@3.25.61", "", {}, "sha512-fzfJgUw78LTNnHujj9re1Ov/JJQkRZZGDMcYqSx7Hp4rPOkKywaFHq0S6GoHeXs0wGNE/sIOutkXgnwzrVOGCQ=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@anatine/esbuild-decorators/esbuild": ["esbuild@0.14.54", "", { "optionalDependencies": { "@esbuild/linux-loong64": "0.14.54", "esbuild-android-64": "0.14.54", "esbuild-android-arm64": "0.14.54", "esbuild-darwin-64": "0.14.54", "esbuild-darwin-arm64": "0.14.54", "esbuild-freebsd-64": "0.14.54", "esbuild-freebsd-arm64": "0.14.54", "esbuild-linux-32": "0.14.54", "esbuild-linux-64": "0.14.54", "esbuild-linux-arm": "0.14.54", "esbuild-linux-arm64": "0.14.54", "esbuild-linux-mips64le": "0.14.54", "esbuild-linux-ppc64le": "0.14.54", "esbuild-linux-riscv64": "0.14.54", "esbuild-linux-s390x": "0.14.54", "esbuild-netbsd-64": "0.14.54", "esbuild-openbsd-64": "0.14.54", "esbuild-sunos-64": "0.14.54", "esbuild-windows-32": "0.14.54", "esbuild-windows-64": "0.14.54", "esbuild-windows-arm64": "0.14.54" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA=="], "@apollo/protobufjs/@types/node": ["@types/node@10.17.60", "", {}, "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="], @@ -3442,18 +3586,28 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], + "@cacheable/memory/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + + "@cacheable/utils/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@csstools/selector-specificity/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], + "@emnapi/core/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + + "@emnapi/runtime/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + + "@emnapi/wasi-threads/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + "@hapi/boom/@hapi/hoek": ["@hapi/hoek@11.0.7", "", {}, "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ=="], "@hapi/joi/@hapi/hoek": ["@hapi/hoek@8.5.1", "", {}, "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow=="], @@ -3464,31 +3618,39 @@ "@hyperswarm/secret-stream/sodium-universal": ["sodium-universal@5.0.1", "", { "dependencies": { "sodium-native": "^5.0.1" }, "peerDependencies": { "sodium-javascript": "~0.8.0" }, "optionalPeers": ["sodium-javascript"] }, "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q=="], + "@iconify/json/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "@iconify/utils/@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], "@iconify/utils/@antfu/utils": ["@antfu/utils@8.1.1", "", {}, "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ=="], "@iconify/utils/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], - "@iconify/utils/local-pkg": ["local-pkg@1.1.1", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.0.1", "quansync": "^0.2.8" } }, "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg=="], + "@iconify/utils/local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], - "@intlify/bundle-utils/@intlify/message-compiler": ["@intlify/message-compiler@11.1.3", "", { "dependencies": { "@intlify/shared": "11.1.3", "source-map-js": "^1.0.2" } }, "sha512-7rbqqpo2f5+tIcwZTAG/Ooy9C8NDVwfDkvSeDPWUPQW+Dyzfw2o9H103N5lKBxO7wxX9dgCDjQ8Umz73uYw3hw=="], + "@intlify/bundle-utils/@intlify/message-compiler": ["@intlify/message-compiler@11.1.12", "", { "dependencies": { "@intlify/shared": "11.1.12", "source-map-js": "^1.0.2" } }, "sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ=="], - "@intlify/bundle-utils/@intlify/shared": ["@intlify/shared@11.1.3", "", {}, "sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA=="], + "@intlify/bundle-utils/@intlify/shared": ["@intlify/shared@11.1.12", "", {}, "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A=="], "@intlify/bundle-utils/yaml-eslint-parser": ["yaml-eslint-parser@1.3.0", "", { "dependencies": { "eslint-visitor-keys": "^3.0.0", "yaml": "^2.0.0" } }, "sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA=="], - "@intlify/unplugin-vue-i18n/@intlify/shared": ["@intlify/shared@11.1.3", "", {}, "sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA=="], + "@intlify/core-base/@intlify/shared": ["@intlify/shared@9.14.5", "", {}, "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ=="], - "@intlify/vue-i18n-extensions/@intlify/shared": ["@intlify/shared@10.0.7", "", {}, "sha512-oeoq0L5+5P4ShXa6jBQcx+BT+USe3MjX0xJexZO1y7rfDJdwZ9+QP3jO4tcS1nxhBYYdjvFTqe4bmnLijV0GxQ=="], + "@intlify/eslint-plugin-vue-i18n/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "@intlify/vue-i18n-extensions/vue-i18n": ["vue-i18n@10.0.7", "", { "dependencies": { "@intlify/core-base": "10.0.7", "@intlify/shared": "10.0.7", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-bKsk0PYwP9gdYF4nqSAT0kDpnLu1gZzlxFl885VH4mHVhEnqP16+/mAU05r1U6NIrc0fGDWP89tZ8GzeJZpe+w=="], + "@intlify/message-compiler/@intlify/shared": ["@intlify/shared@9.14.5", "", {}, "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "@intlify/unplugin-vue-i18n/@intlify/shared": ["@intlify/shared@11.1.12", "", {}, "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A=="], - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + "@intlify/vue-i18n-extensions/@intlify/shared": ["@intlify/shared@10.0.8", "", {}, "sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw=="], - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@intlify/vue-i18n-extensions/vue-i18n": ["vue-i18n@10.0.8", "", { "dependencies": { "@intlify/core-base": "10.0.8", "@intlify/shared": "10.0.8", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-mIjy4utxMz9lMMo6G9vYePv7gUFt4ztOMhY9/4czDJxZ26xPeJ49MAGa9wBAE3XuXbYCrtVPmPxNjej7JJJkZQ=="], + + "@isaacs/cliui/string-width": ["string-width@https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }], + + "@isaacs/cliui/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", { "dependencies": { "ansi-regex": "^6.0.1" } }], + + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }], "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], @@ -3496,17 +3658,25 @@ "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], - "@jest/console/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/console/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@jest/core/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/core/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@jest/create-cache-key-function/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + "@jest/create-cache-key-function/@jest/types": ["@jest/types@30.0.5", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ=="], - "@jest/environment/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/environment/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@jest/fake-timers/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/expect/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], - "@jest/reporters/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/expect/jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], + + "@jest/fake-timers/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/pattern/@types/node": ["@types/node@https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", { "dependencies": { "undici-types": "~6.21.0" } }], + + "@jest/pattern/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + + "@jest/reporters/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "@jest/reporters/istanbul-lib-source-maps": ["istanbul-lib-source-maps@4.0.1", "", { "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" } }, "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw=="], @@ -3514,90 +3684,128 @@ "@jest/reporters/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@jest/snapshot-utils/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "@jest/transform/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], - "@jest/types/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], - - "@ladjs/i18n/qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], - - "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "@morev/utils/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@nuxt/kit/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "@nuxt/kit/ignore": ["ignore@7.0.4", "", {}, "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A=="], + "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@nuxt/kit/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "@nuxt/kit/pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], + "@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + + "@nuxt/kit/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - "@rollup/pluginutils/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "@selderee/plugin-htmlparser2/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], + "@swc-node/register/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "@swc-node/register/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + + "@swc-node/sourcemap-support/source-map-support": ["source-map-support@https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }], + + "@swc-node/sourcemap-support/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + "@swc/cli/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], "@swc/cli/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "@types/accepts/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@swc/cli/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "@types/body-parser/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@swc/jest/@swc/counter": ["@swc/counter@https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", {}], - "@types/connect/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@tybys/wasm-util/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], - "@types/cookies/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/accepts/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/express-serve-static-core/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/body-parser/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/fs-capacitor/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/connect/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/glob/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/cookies/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/graceful-fs/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/express-serve-static-core/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/koa/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/fs-capacitor/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/mysql/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/glob/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/node-fetch/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/graceful-fs/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/send/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/koa/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/serve-static/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/minimatch/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "@types/sodium-native/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/mysql/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@types/node-fetch/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "@types/ws/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@types/nodemailer/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@types/send/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@types/serve-static/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@types/sodium-native/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@types/source-map-support/source-map": ["source-map@https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", {}], + + "@types/ws/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" } }, "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA=="], "@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@7.18.0", "", {}, "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ=="], "@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA=="], - "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], "@vee-validate/yup/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@vitest/mocker/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "@vue/devtools-kit/perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], + + "@vue/reactivity/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + + "@vue/runtime-core/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + + "@vue/runtime-dom/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + + "@vue/server-renderer/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="], + + "@vue/server-renderer/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + + "@xhmikosr/bin-check/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "acorn-globals/acorn": ["acorn@7.4.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="], "acorn-globals/acorn-walk": ["acorn-walk@7.2.0", "", {}, "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="], + "admin/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "ajv-formats/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], "ajv-keywords/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], @@ -3626,6 +3834,8 @@ "apollo-client/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "apollo-graphql/sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], + "apollo-link/ts-invariant": ["ts-invariant@0.4.4", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA=="], "apollo-link/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -3640,6 +3850,12 @@ "apollo-link-http-common/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "apollo-server-core/sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], + + "apollo-server-core/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "apollo-server-env/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "apollo-server-express/@types/body-parser": ["@types/body-parser@1.19.0", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ=="], "apollo-utilities/@wry/equality": ["@wry/equality@0.1.11", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA=="], @@ -3650,23 +3866,35 @@ "babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + "backend/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + + "backend/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + "backend/regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="], + "backend/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "bin-version-check/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], "brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "builtins/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "c12/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "c12/dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], + "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + + "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "c12/pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], + "c12/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "cacheable/keyv": ["keyv@5.3.3", "", { "dependencies": { "@keyv/serialize": "^1.0.3" } }, "sha512-Rwu4+nXI9fqcxiEHtbkvoes2X+QfkTRo1TMkPfwzipGsJlJO/z69vqB4FNl9xJ3xCpAcbkvmEabZfPzrwN3+gQ=="], + "cacheable/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -3688,28 +3916,46 @@ "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "cliui/string-width": ["string-width@https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }], + + "cliui/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], + "concurrently/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "concurrently/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "core/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + + "cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "css-select/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], "css-select/domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], "cssstyle/rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="], - "database/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "database/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + + "database/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], "database/ts-jest": ["ts-jest@27.0.5", "", { "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^27.0.0", "json5": "2.x", "lodash": "4.x", "make-error": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, "optionalPeers": ["@babel/core", "@types/jest", "babel-jest"], "bin": { "ts-jest": "cli.js" } }, "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w=="], + "database/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "decompress-response/mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], "dht-node/@types/jest": ["@types/jest@27.5.1", "", { "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ=="], + "dht-node/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "dht-node/jest": ["jest@27.5.1", "", { "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", "jest-cli": "^27.5.1" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": { "jest": "bin/jest.js" } }, "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ=="], "dht-node/prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], "dht-node/ts-jest": ["ts-jest@27.1.4", "", { "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^27.0.0", "json5": "2.x", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, "optionalPeers": ["@babel/core", "@types/jest", "babel-jest"], "bin": { "ts-jest": "cli.js" } }, "sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ=="], + "dht-node/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "dht-rpc/sodium-universal": ["sodium-universal@5.0.1", "", { "dependencies": { "sodium-native": "^5.0.1" }, "peerDependencies": { "sodium-javascript": "~0.8.0" }, "optionalPeers": ["sodium-javascript"] }, "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q=="], "domexception/webidl-conversions": ["webidl-conversions@5.0.0", "", {}, "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="], @@ -3720,10 +3966,18 @@ "editorconfig/minimatch": ["minimatch@9.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w=="], + "editorconfig/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "email-templates/nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], + "escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "eslint/@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "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" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], + "eslint/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "eslint-compat-utils/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], @@ -3736,27 +3990,35 @@ "eslint-plugin-import/tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + "eslint-plugin-n/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "eslint-plugin-node/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "eslint-plugin-vue/eslint-utils": ["eslint-utils@3.0.0", "", { "dependencies": { "eslint-visitor-keys": "^2.0.0" }, "peerDependencies": { "eslint": ">=5" } }, "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="], + "eslint-plugin-vue/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@1.3.0", "", {}, "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="], + "execa/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "fdir/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "federation/@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="], "federation/apollo-server-testing": ["apollo-server-testing@2.25.2", "", { "dependencies": { "apollo-server-core": "^2.25.2" }, "peerDependencies": { "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" } }, "sha512-HjQV9wPbi/ZqpRbyyhNwCbaDnfjDM0hTRec5TOoOjurEZ/vh4hTPHwGkDZx3kbcWowhGxe2qoHM6KANSB/SxuA=="], + "federation/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "federation/helmet": ["helmet@7.2.0", "", {}, "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw=="], "federation/ts-jest": ["ts-jest@27.0.5", "", { "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^27.0.0", "json5": "2.x", "lodash": "4.x", "make-error": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, "optionalPeers": ["@babel/core", "@types/jest", "babel-jest"], "bin": { "ts-jest": "cli.js" } }, "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w=="], - "file-type/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], + "federation/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], @@ -3764,6 +4026,10 @@ "fixpack/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], + "foreground-child/signal-exit": ["signal-exit@https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", {}], + + "frontend/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "frontend/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], "giget/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], @@ -3776,11 +4042,15 @@ "got/form-data-encoder": ["form-data-encoder@2.1.4", "", {}, "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="], - "graphql-request/form-data": ["form-data@3.0.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.35" } }, "sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w=="], + "graphql-request/form-data": ["form-data@3.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35" } }, "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ=="], "graphql-tools/uuid": ["uuid@3.4.0", "", { "bin": { "uuid": "./bin/uuid" } }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="], - "handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "handlebars/minimist": ["minimist@https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", {}], + + "handlebars/neo-async": ["neo-async@https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", {}], + + "handlebars/source-map": ["source-map@https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", {}], "html-minifier-terser/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], @@ -3792,45 +4062,49 @@ "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "import-from/resolve-from": ["resolve-from@https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", {}], + "is-expression/acorn": ["acorn@7.4.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="], "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "jest-circus/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-circus/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "jest-circus/dedent": ["dedent@0.7.0", "", {}, "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="], "jest-cli/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], - "jest-environment-jsdom/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-environment-jsdom/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "jest-environment-jsdom/jsdom": ["jsdom@16.7.0", "", { "dependencies": { "abab": "^2.0.5", "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", "cssstyle": "^2.3.0", "data-urls": "^2.0.0", "decimal.js": "^10.2.1", "domexception": "^2.0.1", "escodegen": "^2.0.0", "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", "parse5": "6.0.1", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw=="], - "jest-environment-node/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-environment-node/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "jest-haste-map/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-haste-map/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "jest-haste-map/jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], - "jest-jasmine2/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-jasmine2/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "jest-mock/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-mock/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "jest-runner/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-runner/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "jest-runner/jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], "jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], - "jest-serializer/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-serializer/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "jest-util/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-snapshot/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "jest-watcher/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-util/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "jest-worker/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "jest-watcher/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "jest-worker/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "jest-worker/jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="], @@ -3840,15 +4114,19 @@ "jsdom/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + "jsonc-eslint-parser/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "juice/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="], "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "mailparser/html-to-text": ["html-to-text@9.0.5", "", { "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", "dom-serializer": "^2.0.0", "htmlparser2": "^8.0.2", "selderee": "^0.11.0" } }, "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg=="], - "mailparser/nodemailer": ["nodemailer@6.9.16", "", {}, "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ=="], + "mailparser/nodemailer": ["nodemailer@7.0.4", "", {}, "sha512-9O00Vh89/Ld2EcVCqJ/etd7u20UhME0f/NToPfArwPEe1Don1zy4mAIz6ariRr7mJ2RDxtaDzN0WJVdVXPtZaw=="], - "mailparser/tlds": ["tlds@1.255.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw=="], + "mailparser/tlds": ["tlds@1.259.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw=="], + + "make-dir/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -3862,7 +4140,7 @@ "nearley/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "node-fetch/whatwg-url": ["whatwg-url@https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }], "nodemon/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], @@ -3872,15 +4150,21 @@ "noise-curve-ed/sodium-universal": ["sodium-universal@5.0.1", "", { "dependencies": { "sodium-native": "^5.0.1" }, "peerDependencies": { "sodium-javascript": "~0.8.0" }, "optionalPeers": ["sodium-javascript"] }, "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q=="], + "npm-run-path/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "nypm/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "nypm/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "nypm/pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], + "nypm/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "openai/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "nypm/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "openai/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], + + "openai/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "path-scurry/lru-cache": ["lru-cache@https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", {}], "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -3890,6 +4174,8 @@ "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], + "preview-email/nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], + "preview-email/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -3908,12 +4194,22 @@ "seek-bzip/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="], + "semver-truncate/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + "sha.js/inherits": ["inherits@https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", {}], + + "sha.js/safe-buffer": ["safe-buffer@https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", {}], + "shared/@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], + "shared/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + + "shared/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "simple-update-notifier/semver": ["semver@7.0.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="], "sodium-secretstream/sodium-universal": ["sodium-universal@5.0.1", "", { "dependencies": { "sodium-native": "^5.0.1" }, "peerDependencies": { "sodium-javascript": "~0.8.0" }, "optionalPeers": ["sodium-javascript"] }, "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q=="], @@ -3926,11 +4222,19 @@ "streamroller/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + "string-width-cjs/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", {}], + + "string-width-cjs/is-fullwidth-code-point": ["is-fullwidth-code-point@https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}], + + "string-width-cjs/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], + "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "stylelint/file-entry-cache": ["file-entry-cache@10.0.8", "", { "dependencies": { "flat-cache": "^6.1.8" } }, "sha512-FGXHpfmI4XyzbLd3HQ8cbUcsFGohJpZtmQRHr8z8FxxtCe2PcpgIlVLwIgunqjvRmXypBETvwhV4ptJizA+Y1Q=="], + "strip-ansi-cjs/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], - "stylelint/ignore": ["ignore@7.0.4", "", {}, "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A=="], + "stylelint/file-entry-cache": ["file-entry-cache@10.1.4", "", { "dependencies": { "flat-cache": "^6.1.13" } }, "sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA=="], + + "stylelint/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "stylelint/postcss-safe-parser": ["postcss-safe-parser@7.0.1", "", { "peerDependencies": { "postcss": "^8.4.31" } }, "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A=="], @@ -3938,9 +4242,13 @@ "stylelint-config-recommended-scss/stylelint-config-recommended": ["stylelint-config-recommended@14.0.1", "", { "peerDependencies": { "stylelint": "^16.1.0" } }, "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg=="], + "stylelint-config-recommended-vue/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "stylelint-config-standard/stylelint-config-recommended": ["stylelint-config-recommended@14.0.1", "", { "peerDependencies": { "stylelint": "^16.1.0" } }, "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg=="], - "stylelint-scss/mdn-data": ["mdn-data@2.21.0", "", {}, "sha512-+ZKPQezM5vYJIkCxaC+4DTnRrVZR1CgsKLu5zsQERQx6Tea8Y+wMx5A24rq8A8NepCeatIQufVAekKNgiBMsGQ=="], + "stylelint-scss/known-css-properties": ["known-css-properties@0.36.0", "", {}, "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA=="], + + "stylelint-scss/mdn-data": ["mdn-data@2.24.0", "", {}, "sha512-i97fklrJl03tL1tdRVw0ZfLLvuDsdb6wxL+TrJ+PKkCbLrp2PCu2+OYdCKychIUm19nSM/35S6qz7pJpnXttoA=="], "stylelint-scss/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], @@ -3966,55 +4274,63 @@ "test-exclude/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "ts-jest/jest": ["jest@27.5.1", "", { "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", "jest-cli": "^27.5.1" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": { "jest": "bin/jest.js" } }, "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ=="], + "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ts-jest/jest": ["jest@30.2.0", "", { "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", "import-local": "^3.2.0", "jest-cli": "30.2.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": "./bin/jest.js" }, "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A=="], "ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "ts-jest/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], - "typed-rest-client/qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + "type-graphql/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], - "typeorm/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "type-graphql/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "typeorm/dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], + "typeorm/debug": ["debug@https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", { "dependencies": { "ms": "^2.1.3" } }], - "typeorm/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "typeorm/dotenv": ["dotenv@https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", {}], - "typeorm/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + "typeorm/glob": ["glob@https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" } }], + + "typeorm/tslib": ["tslib@https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", {}], + + "typeorm/uuid": ["uuid@https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", {}], "unbzip2-stream/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "unctx/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "unctx/unplugin": ["unplugin@2.3.2", "", { "dependencies": { "acorn": "^8.14.1", "picomatch": "^4.0.2", "webpack-virtual-modules": "^0.6.2" } }, "sha512-3n7YA46rROb3zSj8fFxtxC/PqoyvYQ0llwz9wtUPUutr9ig09C8gGo5CWCwHrUzlqC1LLR43kxp5vEIyH1ac1w=="], + "unctx/unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], "unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], "unimport/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "unimport/local-pkg": ["local-pkg@1.1.1", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.0.1", "quansync": "^0.2.8" } }, "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg=="], + "unimport/local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], "unimport/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "unimport/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "unimport/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "unimport/pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], + "unimport/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "unimport/unplugin": ["unplugin@2.3.2", "", { "dependencies": { "acorn": "^8.14.1", "picomatch": "^4.0.2", "webpack-virtual-modules": "^0.6.2" } }, "sha512-3n7YA46rROb3zSj8fFxtxC/PqoyvYQ0llwz9wtUPUutr9ig09C8gGo5CWCwHrUzlqC1LLR43kxp5vEIyH1ac1w=="], + "unimport/unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], "unplugin-utils/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "unplugin-utils/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "unplugin-utils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "unplugin-vue-components/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "unplugin-vue-components/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.6", "", { "dependencies": { "@vue/devtools-kit": "^7.7.6" } }, "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], @@ -4024,67 +4340,187 @@ "vite-plugin-html/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], - "vite-plugin-html/dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="], + "vite-plugin-html/colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + + "vite-plugin-html/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], "vite-plugin-html/pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], + "vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], + + "vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], + + "vue/@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + "vue-apollo/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], "vue-apollo/throttle-debounce": ["throttle-debounce@2.3.0", "", {}, "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="], + "vue-eslint-parser/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "vue-i18n/@intlify/core-base": ["@intlify/core-base@9.13.1", "", { "dependencies": { "@intlify/message-compiler": "9.13.1", "@intlify/shared": "9.13.1" } }, "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w=="], + "web-resource-inliner/htmlparser2": ["htmlparser2@5.0.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", "domutils": "^2.4.2", "entities": "^2.0.0" } }, "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ=="], "web-resource-inliner/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], + "web-resource-inliner/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "wkx/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "wkx/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }], + + "wrap-ansi/string-width": ["string-width@https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }], + + "wrap-ansi/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], + + "wrap-ansi-cjs/ansi-styles": ["ansi-styles@https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }], + + "wrap-ansi-cjs/string-width": ["string-width@https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], "xss/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "yargs/string-width": ["string-width@https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }], + + "yargs/yargs-parser": ["yargs-parser@https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", {}], + + "@anatine/esbuild-decorators/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw=="], + "@apollographql/graphql-upload-8-fork/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], "@apollographql/graphql-upload-8-fork/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "@hyperswarm/secret-stream/sodium-universal/sodium-native": ["sodium-native@5.0.1", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-Q305aUXc0OzK7VVRvWkeEQJQIHs6slhFwWpyqLB5iJqhpyt2lYIVu96Y6PQ7TABIlWXVF3YiWDU3xS2Snkus+g=="], + "@hyperswarm/secret-stream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], - "@iconify/utils/@antfu/install-pkg/package-manager-detector": ["package-manager-detector@1.3.0", "", {}, "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ=="], + "@iconify/utils/@antfu/install-pkg/package-manager-detector": ["package-manager-detector@1.4.0", "", {}, "sha512-rRZ+pR1Usc+ND9M2NkmCvE/LYJS+8ORVV9X0KuNSY/gFsp7RBHJM/ADh9LYq4Vvfq6QkKrW6/weuh8SMEtN5gw=="], "@iconify/utils/@antfu/install-pkg/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], - "@iconify/utils/local-pkg/pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="], + "@iconify/utils/local-pkg/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "@intlify/bundle-utils/yaml-eslint-parser/yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="], + "@intlify/bundle-utils/yaml-eslint-parser/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], - "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base": ["@intlify/core-base@10.0.7", "", { "dependencies": { "@intlify/message-compiler": "10.0.7", "@intlify/shared": "10.0.7" } }, "sha512-mE71aUH5baH0me8duB4FY5qevUJizypHsYw3eCvmOx07QvmKppgOONx3dYINxuA89Z2qkAGb/K6Nrpi7aAMwew=="], + "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base": ["@intlify/core-base@10.0.8", "", { "dependencies": { "@intlify/message-compiler": "10.0.8", "@intlify/shared": "10.0.8" } }, "sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", {}], - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", {}], - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", {}], "@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "@jest/create-cache-key-function/@jest/types/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@jest/console/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], - "@jest/create-cache-key-function/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@jest/core/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/create-cache-key-function/@jest/types/@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", {}], + + "@jest/create-cache-key-function/@jest/types/@types/istanbul-reports": ["@types/istanbul-reports@https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", { "dependencies": { "@types/istanbul-lib-report": "*" } }], + + "@jest/create-cache-key-function/@jest/types/@types/node": ["@types/node@https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", { "dependencies": { "undici-types": "~6.21.0" } }], + + "@jest/create-cache-key-function/@jest/types/@types/yargs": ["@types/yargs@https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", { "dependencies": { "@types/yargs-parser": "*" } }], + + "@jest/create-cache-key-function/@jest/types/chalk": ["chalk@https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }], + + "@jest/environment/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/expect/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "@jest/expect/expect/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "@jest/expect/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "@jest/expect/expect/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + + "@jest/expect/jest-snapshot/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "@jest/expect/jest-snapshot/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "@jest/expect/jest-snapshot/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "@jest/expect/jest-snapshot/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "@jest/expect/jest-snapshot/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "@jest/expect/jest-snapshot/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + + "@jest/expect/jest-snapshot/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "@jest/expect/jest-snapshot/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + + "@jest/fake-timers/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/pattern/@types/node/undici-types": ["undici-types@https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", {}], + + "@jest/reporters/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], "@jest/reporters/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "@jest/snapshot-utils/@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/snapshot-utils/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@jest/transform/write-file-atomic/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "@nuxt/kit/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "@swc/cli/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "@swc-node/register/debug/ms": ["ms@https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", {}], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "@swc-node/sourcemap-support/source-map-support/buffer-from": ["buffer-from@https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", {}], + + "@swc-node/sourcemap-support/source-map-support/source-map": ["source-map@https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", {}], + + "@swc/cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "@types/accepts/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/body-parser/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/connect/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/cookies/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/express-serve-static-core/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/fs-capacitor/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/glob/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/graceful-fs/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/koa/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/minimatch/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "@types/mysql/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/node-fetch/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/nodemailer/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/send/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/serve-static/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/sodium-native/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@types/ws/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg=="], @@ -4092,15 +4528,25 @@ "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="], + "@vue/server-renderer/@vue/compiler-ssr/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], + + "admin/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "apollo-cache-inmemory/optimism/@wry/context": ["@wry/context@0.4.4", "", { "dependencies": { "@types/node": ">=6", "tslib": "^1.9.3" } }, "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag=="], - "apollo-server-express/@types/body-parser/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "apollo-server-env/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "apollo-server-express/@types/body-parser/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "backend/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -4120,55 +4566,115 @@ "chokidar-cli/yargs/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + "chokidar-cli/yargs/get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "chokidar-cli/yargs/require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "chokidar-cli/yargs/string-width": ["string-width@3.1.0", "", { "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w=="], "chokidar-cli/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], "chokidar-cli/yargs/yargs-parser": ["yargs-parser@13.1.2", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg=="], + "cliui/string-width/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", {}], + + "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], + + "concurrently/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "concurrently/yargs/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "concurrently/yargs/get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "concurrently/yargs/require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "concurrently/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "cross-fetch/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], + "database/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "database/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "database/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "dht-node/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "dht-node/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "dht-node/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - "dht-rpc/sodium-universal/sodium-native": ["sodium-native@5.0.1", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-Q305aUXc0OzK7VVRvWkeEQJQIHs6slhFwWpyqLB5iJqhpyt2lYIVu96Y6PQ7TABIlWXVF3YiWDU3xS2Snkus+g=="], + "dht-rpc/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], - "editorconfig/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "editorconfig/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], "eslint-plugin-vue/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="], + "eslint/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "eslint/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "eslint/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "execa/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "execa/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "execa/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "federation/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "federation/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "federation/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - "file-type/get-stream/is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], - - "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "fixpack/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "frontend/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "global-prefix/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "html-to-text/htmlparser2/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], "html-to-text/htmlparser2/domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], "html-to-text/htmlparser2/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], - "hypercore-crypto/sodium-universal/sodium-native": ["sodium-native@5.0.1", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-Q305aUXc0OzK7VVRvWkeEQJQIHs6slhFwWpyqLB5iJqhpyt2lYIVu96Y6PQ7TABIlWXVF3YiWDU3xS2Snkus+g=="], + "hypercore-crypto/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + + "jest-circus/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], "jest-cli/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + "jest-cli/yargs/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "jest-cli/yargs/get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "jest-cli/yargs/require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "jest-cli/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "jest-cli/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "jest-environment-jsdom/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "jest-environment-jsdom/jsdom/cssstyle": ["cssstyle@2.3.0", "", { "dependencies": { "cssom": "~0.3.6" } }, "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="], "jest-environment-jsdom/jsdom/data-urls": ["data-urls@2.0.0", "", { "dependencies": { "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.0.0" } }, "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ=="], - "jest-environment-jsdom/jsdom/form-data": ["form-data@3.0.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.35" } }, "sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w=="], + "jest-environment-jsdom/jsdom/form-data": ["form-data@3.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35" } }, "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ=="], "jest-environment-jsdom/jsdom/html-encoding-sniffer": ["html-encoding-sniffer@2.0.1", "", { "dependencies": { "whatwg-encoding": "^1.0.5" } }, "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ=="], @@ -4194,32 +4700,62 @@ "jest-environment-jsdom/jsdom/xml-name-validator": ["xml-name-validator@3.0.0", "", {}, "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="], + "jest-environment-node/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "jest-jasmine2/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-mock/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-runner/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "jest-runner/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "jest-serializer/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-util/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-watcher/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "jest-worker/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "jest-worker/jest-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + "js-beautify/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "js-beautify/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "js-beautify/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "jsdom/parse5/entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="], + "js-beautify/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "js-beautify/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "js-beautify/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "jsdom/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "mailparser/html-to-text/@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], "mailparser/html-to-text/selderee": ["selderee@0.11.0", "", { "dependencies": { "parseley": "^0.12.0" } }, "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA=="], - "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "node-fetch/whatwg-url/tr46": ["tr46@https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", {}], - "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", {}], "nodemon/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "nodemon/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "noise-curve-ed/sodium-universal/sodium-native": ["sodium-native@5.0.1", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-Q305aUXc0OzK7VVRvWkeEQJQIHs6slhFwWpyqLB5iJqhpyt2lYIVu96Y6PQ7TABIlWXVF3YiWDU3xS2Snkus+g=="], + "noise-curve-ed/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], "nypm/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "openai/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "run-applescript/execa/cross-spawn": ["cross-spawn@6.0.6", "", { "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw=="], @@ -4236,27 +4772,53 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "sodium-secretstream/sodium-universal/sodium-native": ["sodium-native@5.0.1", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-Q305aUXc0OzK7VVRvWkeEQJQIHs6slhFwWpyqLB5iJqhpyt2lYIVu96Y6PQ7TABIlWXVF3YiWDU3xS2Snkus+g=="], + "sodium-secretstream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], "streamroller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "streamroller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.8", "", { "dependencies": { "cacheable": "^1.8.9", "flatted": "^3.3.3", "hookified": "^1.8.1" } }, "sha512-R6MaD3nrJAtO7C3QOuS79ficm2pEAy++TgEUD8ii1LVlbcgZ9DtASLkt9B+RZSFCzm7QHDMlXPsqqB6W2Pfr1Q=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], + + "stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.17", "", { "dependencies": { "cacheable": "^2.0.3", "flatted": "^3.3.3", "hookified": "^1.12.0" } }, "sha512-Jzse4YoiUJBVYTwz5Bwl4h/2VQM7e2KK3MVAMlXzX9uamIHAH/TXUlRKU1AQGQOryQhN0EsmufiiF40G057YXA=="], "table/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "terminal-link/supports-hyperlinks/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "terser-webpack-plugin/jest-worker/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "terser-webpack-plugin/jest-worker/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], "terser-webpack-plugin/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "test-exclude/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "test-exclude/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "typeorm/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "test-exclude/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "unctx/unplugin/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "test-exclude/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "test-exclude/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "test-exclude/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ts-jest/jest/@jest/core": ["@jest/core@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", "@jest/reporters": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "ci-info": "^4.2.0", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", "jest-changed-files": "30.2.0", "jest-config": "30.2.0", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-resolve-dependencies": "30.2.0", "jest-runner": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "jest-watcher": "30.2.0", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"] }, "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ=="], + + "ts-jest/jest/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "ts-jest/jest/jest-cli": ["jest-cli@30.2.0", "", { "dependencies": { "@jest/core": "30.2.0", "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", "jest-config": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "yargs": "^17.7.2" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": { "jest": "./bin/jest.js" } }, "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA=="], + + "type-graphql/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "typeorm/debug/ms": ["ms@https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", {}], + + "typeorm/glob/minimatch": ["minimatch@https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", { "dependencies": { "brace-expansion": "^2.0.1" } }], + + "unbzip2-stream/buffer/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "unbzip2-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "unctx/unplugin/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "unimport/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], @@ -4264,51 +4826,51 @@ "unplugin-vue-components/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "unplugin-vue-components/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "unplugin-vue-components/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", {}, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], - "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", {}, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], - "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", {}, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], - "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", {}, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], - "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", {}, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], - "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", {}, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], - "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", {}, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], - "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", {}, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], - "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", {}, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], - "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", {}, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], - "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", {}, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], - "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", {}, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], - "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", {}, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], - "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", {}, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], - "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", {}, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], - "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", {}, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], - "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", {}, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], - "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", {}, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], - "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", {}, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], - "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", {}, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], - "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", {}, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], - "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", {}, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], @@ -4316,29 +4878,141 @@ "vue-apollo/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + "vue-i18n/@intlify/core-base/@intlify/message-compiler": ["@intlify/message-compiler@9.13.1", "", { "dependencies": { "@intlify/shared": "9.13.1", "source-map-js": "^1.0.2" } }, "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w=="], + + "vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], + + "vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], + + "vue/@vue/compiler-sfc/@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="], + "web-resource-inliner/htmlparser2/domhandler": ["domhandler@3.3.0", "", { "dependencies": { "domelementtype": "^2.0.1" } }, "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA=="], "web-resource-inliner/htmlparser2/domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], "web-resource-inliner/htmlparser2/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "web-resource-inliner/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], + "wkx/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", { "dependencies": { "color-name": "~1.1.4" } }], + + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", {}], + + "wrap-ansi-cjs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}], + + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], + + "wrap-ansi/ansi-styles/color-convert": ["color-convert@https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", { "dependencies": { "color-name": "~1.1.4" } }], + + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", {}], + + "wrap-ansi/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], + + "yargs/string-width/emoji-regex": ["emoji-regex@https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", {}], + + "yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}], + + "yargs/string-width/strip-ansi": ["strip-ansi@https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }], + "@iconify/utils/local-pkg/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], "@iconify/utils/local-pkg/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base/@intlify/message-compiler": ["@intlify/message-compiler@10.0.7", "", { "dependencies": { "@intlify/shared": "10.0.7", "source-map-js": "^1.0.2" } }, "sha512-nrC4cDL/UHZSUqd8sRbVz+DPukzZ8NnG5OK+EB/nlxsH35deyzyVkXP/QuR8mFZrISJ+4hCd6VtCQCcT+RO+5g=="], + "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base/@intlify/message-compiler": ["@intlify/message-compiler@10.0.8", "", { "dependencies": { "@intlify/shared": "10.0.8", "source-map-js": "^1.0.2" } }, "sha512-DV+sYXIkHVd5yVb2mL7br/NEUwzUoLBsMkV3H0InefWgmYa34NLZUvMCGi5oWX+Hqr2Y2qUxnVrnOWF4aBlgWg=="], "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + "@jest/create-cache-key-function/@jest/types/@types/istanbul-reports/@types/istanbul-lib-report": ["@types/istanbul-lib-report@https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", { "dependencies": { "@types/istanbul-lib-coverage": "*" } }], + + "@jest/create-cache-key-function/@jest/types/@types/node/undici-types": ["undici-types@https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", {}], + + "@jest/create-cache-key-function/@jest/types/@types/yargs/@types/yargs-parser": ["@types/yargs-parser@https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", {}], + + "@jest/create-cache-key-function/@jest/types/chalk/ansi-styles": ["ansi-styles@https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }], + + "@jest/create-cache-key-function/@jest/types/chalk/supports-color": ["supports-color@https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }], + + "@jest/expect/expect/jest-matcher-utils/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "@jest/expect/expect/jest-matcher-utils/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "@jest/expect/expect/jest-message-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "@jest/expect/expect/jest-message-util/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "@jest/expect/expect/jest-mock/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "@jest/expect/expect/jest-mock/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/expect/jest-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + + "@jest/expect/expect/jest-util/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/expect/jest-util/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "@jest/expect/expect/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "@jest/expect/jest-snapshot/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "@jest/expect/jest-snapshot/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + + "@jest/expect/jest-snapshot/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "@jest/expect/jest-snapshot/@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/jest-snapshot/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@jest/expect/jest-snapshot/jest-util/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/jest-snapshot/jest-util/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "@jest/expect/jest-snapshot/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "@jest/expect/jest-snapshot/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "@jest/expect/jest-snapshot/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "@jest/snapshot-utils/@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "@swc/cli/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@types/minimatch/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "apollo-cache-inmemory/optimism/@wry/context/@types/node": ["@types/node@18.19.96", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-PzBvgsZ7YdFs/Kng1BSW8IGv68/SPcOxYYhT7luxD7QyzIhFS1xPTpfK3K9eHBa7hVwlW+z8nN0mOd515yaduQ=="], + "@vue/server-renderer/@vue/compiler-ssr/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], + + "admin/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "admin/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "admin/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "apollo-cache-inmemory/optimism/@wry/context/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "apollo-server-env/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "apollo-server-env/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "apollo-server-express/@types/body-parser/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "backend/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "backend/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "backend/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "cheerio-select/domutils/dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], @@ -4356,14 +5030,54 @@ "chokidar-cli/yargs/yargs-parser/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + "concurrently/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "cross-fetch/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "cross-fetch/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "css-select/domutils/dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "database/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "database/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "database/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "dht-node/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "dht-node/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "dht-node/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "editorconfig/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "eslint/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "eslint/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "execa/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "execa/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "federation/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "federation/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "federation/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "frontend/cross-env/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "frontend/cross-env/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "frontend/cross-env/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "html-to-text/htmlparser2/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], + "jest-cli/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "jest-environment-jsdom/jsdom/cssstyle/cssom": ["cssom@0.3.8", "", {}, "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="], "jest-environment-jsdom/jsdom/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], @@ -4376,12 +5090,26 @@ "jest-environment-jsdom/jsdom/whatwg-url/tr46": ["tr46@2.1.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw=="], + "jest-worker/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + "jest-worker/jest-util/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], - "js-beautify/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "js-beautify/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "js-beautify/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "js-beautify/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "mailparser/html-to-text/selderee/parseley": ["parseley@0.12.1", "", { "dependencies": { "leac": "^0.6.0", "peberminta": "^0.9.0" } }, "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw=="], + "openai/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "openai/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "run-applescript/execa/cross-spawn/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="], @@ -4394,9 +5122,73 @@ "run-applescript/execa/npm-run-path/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="], + "terser-webpack-plugin/jest-worker/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "test-exclude/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "test-exclude/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "test-exclude/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "typeorm/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "ts-jest/jest/@jest/core/@jest/console": ["@jest/console@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0" } }, "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ=="], + + "ts-jest/jest/@jest/core/@jest/reporters": ["@jest/reporters@30.2.0", "", { "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", "chalk": "^4.1.2", "collect-v8-coverage": "^1.0.2", "exit-x": "^0.2.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "jest-worker": "30.2.0", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"] }, "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ=="], + + "ts-jest/jest/@jest/core/@jest/test-result": ["@jest/test-result@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/types": "30.2.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" } }, "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg=="], + + "ts-jest/jest/@jest/core/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "ts-jest/jest/@jest/core/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/@jest/core/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "ts-jest/jest/@jest/core/jest-changed-files": ["jest-changed-files@30.2.0", "", { "dependencies": { "execa": "^5.1.1", "jest-util": "30.2.0", "p-limit": "^3.1.0" } }, "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ=="], + + "ts-jest/jest/@jest/core/jest-config": ["jest-config@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", "@jest/pattern": "30.0.1", "@jest/test-sequencer": "30.2.0", "@jest/types": "30.2.0", "babel-jest": "30.2.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "jest-circus": "30.2.0", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-runner": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "micromatch": "^4.0.8", "parse-json": "^5.2.0", "pretty-format": "30.2.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "peerDependencies": { "@types/node": "*", "esbuild-register": ">=3.4.0", "ts-node": ">=9.0.0" }, "optionalPeers": ["@types/node", "esbuild-register", "ts-node"] }, "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA=="], + + "ts-jest/jest/@jest/core/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/@jest/core/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "ts-jest/jest/@jest/core/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + + "ts-jest/jest/@jest/core/jest-resolve": ["jest-resolve@30.2.0", "", { "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-pnp-resolver": "^1.2.3", "jest-util": "30.2.0", "jest-validate": "30.2.0", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" } }, "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A=="], + + "ts-jest/jest/@jest/core/jest-resolve-dependencies": ["jest-resolve-dependencies@30.2.0", "", { "dependencies": { "jest-regex-util": "30.0.1", "jest-snapshot": "30.2.0" } }, "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w=="], + + "ts-jest/jest/@jest/core/jest-runner": ["jest-runner@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/environment": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-haste-map": "30.2.0", "jest-leak-detector": "30.2.0", "jest-message-util": "30.2.0", "jest-resolve": "30.2.0", "jest-runtime": "30.2.0", "jest-util": "30.2.0", "jest-watcher": "30.2.0", "jest-worker": "30.2.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ=="], + + "ts-jest/jest/@jest/core/jest-runtime": ["jest-runtime@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg=="], + + "ts-jest/jest/@jest/core/jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], + + "ts-jest/jest/@jest/core/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + + "ts-jest/jest/@jest/core/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], + + "ts-jest/jest/@jest/core/jest-watcher": ["jest-watcher@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", "jest-util": "30.2.0", "string-length": "^4.0.2" } }, "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg=="], + + "ts-jest/jest/@jest/core/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "ts-jest/jest/@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "ts-jest/jest/jest-cli/@jest/test-result": ["@jest/test-result@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/types": "30.2.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" } }, "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg=="], + + "ts-jest/jest/jest-cli/jest-config": ["jest-config@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", "@jest/pattern": "30.0.1", "@jest/test-sequencer": "30.2.0", "@jest/types": "30.2.0", "babel-jest": "30.2.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "jest-circus": "30.2.0", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-runner": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "micromatch": "^4.0.8", "parse-json": "^5.2.0", "pretty-format": "30.2.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "peerDependencies": { "@types/node": "*", "esbuild-register": ">=3.4.0", "ts-node": ">=9.0.0" }, "optionalPeers": ["@types/node", "esbuild-register", "ts-node"] }, "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA=="], + + "ts-jest/jest/jest-cli/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + + "ts-jest/jest/jest-cli/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], + + "ts-jest/jest/jest-cli/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "typeorm/glob/minimatch/brace-expansion": ["brace-expansion@https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }], "unplugin-vue-components/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -4406,10 +5198,68 @@ "web-resource-inliner/htmlparser2/domutils/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], + "web-resource-inliner/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "web-resource-inliner/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", {}], + + "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", {}], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", {}], + + "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base/@intlify/message-compiler/source-map-js": ["source-map-js@https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", {}], + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "@jest/create-cache-key-function/@jest/types/chalk/ansi-styles/color-convert": ["color-convert@https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", { "dependencies": { "color-name": "~1.1.4" } }], + + "@jest/create-cache-key-function/@jest/types/chalk/supports-color/has-flag": ["has-flag@https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", {}], + + "@jest/expect/expect/jest-matcher-utils/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "@jest/expect/expect/jest-matcher-utils/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "@jest/expect/expect/jest-message-util/@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/expect/jest-message-util/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@jest/expect/expect/jest-message-util/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "@jest/expect/expect/jest-message-util/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "@jest/expect/expect/jest-mock/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@jest/expect/expect/jest-mock/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/expect/jest-util/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + + "@jest/expect/expect/jest-util/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/jest-snapshot/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "@jest/expect/jest-snapshot/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "@jest/expect/jest-snapshot/@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/jest-snapshot/jest-util/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "admin/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "admin/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "apollo-cache-inmemory/optimism/@wry/context/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "backend/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "backend/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "chokidar-cli/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], "chokidar-cli/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], @@ -4420,20 +5270,806 @@ "chokidar-cli/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + "database/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "database/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "dht-node/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "dht-node/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "federation/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "federation/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "frontend/cross-env/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "frontend/cross-env/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jest-worker/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + + "js-beautify/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "js-beautify/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "js-beautify/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "js-beautify/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "run-applescript/execa/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@1.0.0", "", {}, "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ=="], - "typeorm/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "run-applescript/execa/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "test-exclude/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "test-exclude/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "test-exclude/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/@jest/core/@jest/reporters/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/@jest/core/@jest/reporters/v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="], + + "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/@jest/core/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/@jest/core/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "ts-jest/jest/@jest/core/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/@jest/core/jest-config/@jest/test-sequencer": ["@jest/test-sequencer@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "slash": "^3.0.0" } }, "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest": ["babel-jest@30.2.0", "", { "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw=="], + + "ts-jest/jest/@jest/core/jest-config/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus": ["jest-circus@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", "jest-each": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "p-limit": "^3.1.0", "pretty-format": "30.2.0", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg=="], + + "ts-jest/jest/@jest/core/jest-config/jest-docblock": ["jest-docblock@30.2.0", "", { "dependencies": { "detect-newline": "^3.1.0" } }, "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], + + "ts-jest/jest/@jest/core/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/@jest/core/jest-runner/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/@jest/core/jest-runner/emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-docblock": ["jest-docblock@30.2.0", "", { "dependencies": { "detect-newline": "^3.1.0" } }, "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-leak-detector": ["jest-leak-detector@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" } }, "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/@jest/core/jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/globals": ["@jest/globals@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/types": "30.2.0", "jest-mock": "30.2.0" } }, "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/source-map": ["@jest/source-map@30.0.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", "graceful-fs": "^4.2.11" } }, "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg=="], + + "ts-jest/jest/@jest/core/jest-runtime/cjs-module-lexer": ["cjs-module-lexer@2.1.0", "", {}, "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "ts-jest/jest/@jest/core/jest-runtime/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/@jest/core/jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "ts-jest/jest/@jest/core/jest-snapshot/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], + + "ts-jest/jest/@jest/core/jest-snapshot/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "ts-jest/jest/@jest/core/jest-snapshot/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "ts-jest/jest/@jest/core/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "ts-jest/jest/@jest/core/jest-watcher/emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="], + + "ts-jest/jest/@jest/core/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "ts-jest/jest/@jest/core/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "ts-jest/jest/@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console": ["@jest/console@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0" } }, "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer": ["@jest/test-sequencer@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "slash": "^3.0.0" } }, "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest": ["babel-jest@30.2.0", "", { "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw=="], + + "ts-jest/jest/jest-cli/jest-config/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "ts-jest/jest/jest-cli/jest-config/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus": ["jest-circus@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", "jest-each": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "p-limit": "^3.1.0", "pretty-format": "30.2.0", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-docblock": ["jest-docblock@30.2.0", "", { "dependencies": { "detect-newline": "^3.1.0" } }, "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve": ["jest-resolve@30.2.0", "", { "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-pnp-resolver": "^1.2.3", "jest-util": "30.2.0", "jest-validate": "30.2.0", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" } }, "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner": ["jest-runner@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/environment": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", "jest-docblock": "30.2.0", "jest-environment-node": "30.2.0", "jest-haste-map": "30.2.0", "jest-leak-detector": "30.2.0", "jest-message-util": "30.2.0", "jest-resolve": "30.2.0", "jest-runtime": "30.2.0", "jest-util": "30.2.0", "jest-watcher": "30.2.0", "jest-worker": "30.2.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ=="], + + "ts-jest/jest/jest-cli/jest-config/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "ts-jest/jest/jest-cli/jest-util/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-util/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "ts-jest/jest/jest-cli/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "ts-jest/jest/jest-cli/jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "ts-jest/jest/jest-cli/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "ts-jest/jest/jest-cli/yargs/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "ts-jest/jest/jest-cli/yargs/get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "ts-jest/jest/jest-cli/yargs/require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "ts-jest/jest/jest-cli/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "typeorm/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", {}], "vue-apollo/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + "@jest/create-cache-key-function/@jest/types/chalk/ansi-styles/color-convert/color-name": ["color-name@https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", {}], + + "@jest/expect/expect/jest-message-util/@jest/types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "chokidar-cli/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], "chokidar-cli/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "js-beautify/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "js-beautify/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "js-beautify/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "test-exclude/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "test-exclude/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/@jest/core/@jest/reporters/v8-to-istanbul/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-preset-jest": ["babel-preset-jest@30.2.0", "", { "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "ts-jest/jest/@jest/core/jest-config/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "ts-jest/jest/@jest/core/jest-config/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "ts-jest/jest/@jest/core/jest-config/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "ts-jest/jest/@jest/core/jest-config/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/jest-each": ["jest-each@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "chalk": "^4.1.2", "jest-util": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/@jest/core/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/@jest/core/jest-runner/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/@jest/core/jest-runner/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/@jest/core/jest-runner/source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "ts-jest/jest/@jest/core/jest-snapshot/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-preset-jest": ["babel-preset-jest@30.2.0", "", { "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "ts-jest/jest/jest-cli/jest-config/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "ts-jest/jest/jest-cli/jest-config/glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "ts-jest/jest/jest-cli/jest-config/glob/package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "ts-jest/jest/jest-cli/jest-config/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-each": ["jest-each@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "chalk": "^4.1.2", "jest-util": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime": ["jest-runtime@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/console": ["@jest/console@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0" } }, "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/emittery": ["emittery@0.13.1", "", {}, "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-leak-detector": ["jest-leak-detector@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" } }, "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime": ["jest-runtime@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-watcher": ["jest-watcher@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", "jest-util": "30.2.0", "string-length": "^4.0.2" } }, "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="], + + "ts-jest/jest/jest-cli/jest-config/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "ts-jest/jest/jest-cli/jest-config/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "ts-jest/jest/jest-cli/jest-util/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-validate/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "ts-jest/jest/jest-cli/jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "ts-jest/jest/jest-cli/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "chokidar-cli/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-preset-jest/babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "^7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "ts-jest/jest/@jest/core/jest-config/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ts-jest/jest/@jest/core/jest-config/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/jest-matcher-utils/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/@jest/core/jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/@jest/core/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/jest-message-util/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-preset-jest/babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "^7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "ts-jest/jest/jest-cli/jest-config/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ts-jest/jest/jest-cli/jest-config/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-matcher-utils/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/globals": ["@jest/globals@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/types": "30.2.0", "jest-mock": "30.2.0" } }, "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/source-map": ["@jest/source-map@30.0.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", "graceful-fs": "^4.2.11" } }, "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/cjs-module-lexer": ["cjs-module-lexer@2.1.0", "", {}, "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@jest/fake-timers/jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve/jest-haste-map/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/@jest/globals": ["@jest/globals@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", "@jest/types": "30.2.0", "jest-mock": "30.2.0" } }, "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/@jest/source-map": ["@jest/source-map@30.0.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", "graceful-fs": "^4.2.11" } }, "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/cjs-module-lexer": ["cjs-module-lexer@2.1.0", "", {}, "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "ts-jest/jest/@jest/core/jest-config/babel-jest/babel-plugin-istanbul/test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ts-jest/jest/@jest/core/jest-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/@jest/core/jest-config/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/@jest/core/jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/@jest/core/jest-runner/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/jest-message-util/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "ts-jest/jest/jest-cli/@jest/test-result/@jest/console/jest-message-util/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/babel-plugin-istanbul/test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn/path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn/shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ts-jest/jest/jest-cli/jest-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve/jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-resolve/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/jest-snapshot/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/jest-snapshot/jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/jest-snapshot/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/@jest/reporters/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "ts-jest/jest/@jest/core/jest-config/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-config/jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/@jest/core/jest-runtime/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "ts-jest/jest/jest-cli/jest-config/glob/foreground-child/cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/string-width/eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "ts-jest/jest/jest-cli/jest-config/glob/jackspeak/@isaacs/cliui/wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/babel-plugin-istanbul/test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-runner/jest-runtime/@jest/fake-timers/@sinonjs/fake-timers/@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/babel-plugin-istanbul/test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/babel-plugin-istanbul/test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], } } From 6b89e1d43c03b3976696b6cc6135a642f8737979 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 7 Oct 2025 15:49:36 +0200 Subject: [PATCH 040/226] update npm packages and lint --- .../resolver/TransactionLinkResolver.test.ts | 3 + .../resolver/TransactionResolver.test.ts | 3 + bun.lock | 176 ++++++++++++++---- database/src/AppDatabase.ts | 7 +- database/src/entity/Community.ts | 2 +- database/src/entity/Contribution.ts | 2 +- database/src/entity/DltTransaction.ts | 17 +- database/src/entity/Event.ts | 2 +- database/src/entity/Transaction.ts | 22 ++- database/src/entity/TransactionLink.ts | 30 ++- database/src/entity/User.ts | 16 +- database/src/index.ts | 2 +- database/src/logging/AbstractLogging.view.ts | 3 +- .../logging/PendingTransactionLogging.view.ts | 2 +- .../src/logging/UserContactLogging.view.ts | 12 +- database/src/logging/UserLogging.view.ts | 2 +- database/src/logging/UserRoleLogging.view.ts | 12 +- database/src/queries/communities.test.ts | 8 +- database/src/queries/communities.ts | 24 +-- database/src/queries/events.ts | 30 ++- database/src/queries/index.ts | 8 +- .../src/queries/pendingTransactions.test.ts | 81 ++++---- database/src/queries/pendingTransactions.ts | 6 +- database/src/queries/transactionLinks.ts | 2 +- database/src/queries/user.test.ts | 41 ++-- database/src/queries/user.ts | 23 ++- database/src/seeds/community.ts | 64 +++---- .../src/seeds/factory/pendingTransaction.ts | 8 +- database/src/seeds/factory/user.ts | 16 +- database/src/seeds/users/peter-lustig.ts | 2 +- database/src/util/index.ts | 2 +- package.json | 2 +- shared/tsconfig.json | 6 +- yarn.lock | 75 +++++++- 34 files changed, 474 insertions(+), 237 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index d7c2fc713..b6abcb0b2 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -37,11 +37,14 @@ import { TRANSACTIONS_LOCK } from 'database' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLogger } from 'config-schema/test/testSetup' import { transactionLinkCode } from './TransactionLinkResolver' +import { CONFIG } from '@/config' const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) jest.mock('@/password/EncryptorUtils') +CONFIG.DLT_CONNECTOR = false + // mock semaphore to allow use fake timers jest.mock('database/src/util/TRANSACTIONS_LOCK') TRANSACTIONS_LOCK.acquire = jest.fn().mockResolvedValue(jest.fn()) diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 7fc4630f8..c6cc69250 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -33,10 +33,13 @@ import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' import { getLogger } from 'config-schema/test/testSetup' +import { CONFIG } from '@/config' jest.mock('@/password/EncryptorUtils') const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) +CONFIG.DLT_CONNECTOR = false +CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] diff --git a/bun.lock b/bun.lock index 88deb2864..223e7dcfa 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ "uuid": "^8.3.2", }, "devDependencies": { - "@biomejs/biome": "2.0.0", + "@biomejs/biome": "^2.2.5", }, }, "admin": { @@ -544,23 +544,23 @@ "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], - "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "@biomejs/biome": ["@biomejs/biome@2.2.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.5", "@biomejs/cli-darwin-x64": "2.2.5", "@biomejs/cli-linux-arm64": "2.2.5", "@biomejs/cli-linux-arm64-musl": "2.2.5", "@biomejs/cli-linux-x64": "2.2.5", "@biomejs/cli-linux-x64-musl": "2.2.5", "@biomejs/cli-win32-arm64": "2.2.5", "@biomejs/cli-win32-x64": "2.2.5" }, "bin": { "biome": "bin/biome" } }, "sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.5", "", { "os": "win32", "cpu": "x64" }, "sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw=="], "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], @@ -1674,7 +1674,7 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -2760,7 +2760,7 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -3586,8 +3586,6 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -3688,6 +3686,8 @@ "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], @@ -3696,14 +3696,14 @@ "@jest/types/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "@morev/utils/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@nuxt/kit/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "@nuxt/kit/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -3866,6 +3866,8 @@ "babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + "backend/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "backend/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], "backend/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], @@ -3888,8 +3890,6 @@ "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "c12/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -3924,6 +3924,10 @@ "concurrently/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "config-schema/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + + "core/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "core/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], "cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -3934,6 +3938,8 @@ "cssstyle/rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="], + "database/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "database/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="], "database/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], @@ -3944,6 +3950,8 @@ "decompress-response/mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + "dht-node/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "dht-node/@types/jest": ["@types/jest@27.5.1", "", { "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ=="], "dht-node/cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], @@ -4008,6 +4016,8 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "federation/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "federation/@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="], "federation/apollo-server-testing": ["apollo-server-testing@2.25.2", "", { "dependencies": { "apollo-server-core": "^2.25.2" }, "peerDependencies": { "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" } }, "sha512-HjQV9wPbi/ZqpRbyyhNwCbaDnfjDM0hTRec5TOoOjurEZ/vh4hTPHwGkDZx3kbcWowhGxe2qoHM6KANSB/SxuA=="], @@ -4204,6 +4214,8 @@ "sha.js/safe-buffer": ["safe-buffer@https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", {}], + "shared/@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], + "shared/@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], "shared/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], @@ -4330,6 +4342,8 @@ "update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], @@ -4546,6 +4560,22 @@ "apollo-server-express/@types/body-parser/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], + "backend/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "backend/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "backend/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "backend/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "backend/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "backend/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "backend/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "backend/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "backend/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -4592,16 +4622,80 @@ "concurrently/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "config-schema/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "config-schema/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "config-schema/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "config-schema/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "config-schema/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "config-schema/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "config-schema/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "config-schema/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + + "core/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "core/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "core/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "core/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "core/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "core/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "core/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "core/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "cross-fetch/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], "css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], + "database/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "database/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "database/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "database/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "database/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "database/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "database/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "database/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "database/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "database/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "database/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "dht-node/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "dht-node/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "dht-node/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "dht-node/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "dht-node/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "dht-node/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "dht-node/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "dht-node/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "dht-node/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "dht-node/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], @@ -4630,6 +4724,22 @@ "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "federation/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "federation/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "federation/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "federation/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "federation/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "federation/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "federation/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "federation/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "federation/cross-env/cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "federation/ts-jest/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], @@ -4772,6 +4882,22 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "shared/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", {}, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="], + + "shared/@biomejs/biome/@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", {}, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="], + + "shared/@biomejs/biome/@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", {}, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="], + + "shared/@biomejs/biome/@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", {}, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="], + + "shared/@biomejs/biome/@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", {}, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="], + + "shared/@biomejs/biome/@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", {}, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="], + + "shared/@biomejs/biome/@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", {}, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="], + + "shared/@biomejs/biome/@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", {}, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="], + "sodium-secretstream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], "streamroller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], @@ -4960,8 +5086,6 @@ "@jest/expect/jest-snapshot/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "@jest/expect/jest-snapshot/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "@jest/expect/jest-snapshot/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], "@jest/expect/jest-snapshot/@jest/transform/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], @@ -5342,8 +5466,6 @@ "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "ts-jest/jest/@jest/core/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/@jest/core/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "ts-jest/jest/@jest/core/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], @@ -5516,8 +5638,6 @@ "ts-jest/jest/@jest/core/@jest/reporters/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "ts-jest/jest/@jest/core/@jest/reporters/v8-to-istanbul/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], "ts-jest/jest/@jest/core/@jest/transform/babel-plugin-istanbul/test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], @@ -5728,8 +5848,6 @@ "ts-jest/jest/jest-cli/jest-config/@jest/test-sequencer/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], "ts-jest/jest/jest-cli/jest-config/babel-jest/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], @@ -5796,8 +5914,6 @@ "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/jest-cli/jest-config/jest-runner/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "ts-jest/jest/jest-cli/jest-config/jest-runner/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], @@ -5930,16 +6046,12 @@ "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-runtime/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], "ts-jest/jest/jest-cli/jest-config/jest-circus/jest-snapshot/@jest/transform/pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts index f995a176a..e29a09965 100644 --- a/database/src/AppDatabase.ts +++ b/database/src/AppDatabase.ts @@ -1,10 +1,9 @@ -import { DataSource as DBDataSource, FileLogger } from 'typeorm' -import { Migration, entities } from './entity' - import { getLogger } from 'log4js' +import { DataSource as DBDataSource, FileLogger } from 'typeorm' import { latestDbVersion } from '.' import { CONFIG } from './config' import { LOG4JS_BASE_CATEGORY_NAME } from './config/const' +import { entities, Migration } from './entity' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.AppDatabase`) @@ -93,7 +92,7 @@ export class AppDatabase { public async destroy(): Promise { await this.dataSource?.destroy() } - + // ###################################### // private methods // ###################################### diff --git a/database/src/entity/Community.ts b/database/src/entity/Community.ts index f6597306a..af9cc1e7d 100644 --- a/database/src/entity/Community.ts +++ b/database/src/entity/Community.ts @@ -10,8 +10,8 @@ import { UpdateDateColumn, } from 'typeorm' import { FederatedCommunity } from './FederatedCommunity' -import { User } from './User' import { GeometryTransformer } from './transformer/GeometryTransformer' +import { User } from './User' @Entity('communities') export class Community extends BaseEntity { diff --git a/database/src/entity/Contribution.ts b/database/src/entity/Contribution.ts index 976385263..a2f410e1d 100644 --- a/database/src/entity/Contribution.ts +++ b/database/src/entity/Contribution.ts @@ -12,8 +12,8 @@ import { } from 'typeorm' import { ContributionMessage } from './ContributionMessage' import { Transaction } from './Transaction' -import { User } from './User' import { DecimalTransformer } from './transformer/DecimalTransformer' +import { User } from './User' @Entity('contributions') export class Contribution extends BaseEntity { diff --git a/database/src/entity/DltTransaction.ts b/database/src/entity/DltTransaction.ts index adb581490..2df3fb92c 100644 --- a/database/src/entity/DltTransaction.ts +++ b/database/src/entity/DltTransaction.ts @@ -1,7 +1,7 @@ import { BaseEntity, Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm' import { Transaction } from './Transaction' -import { User } from './User' import { TransactionLink } from './TransactionLink' +import { User } from './User' @Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class DltTransaction extends BaseEntity { @@ -48,15 +48,24 @@ export class DltTransaction extends BaseEntity { @Column({ name: 'error', type: 'text', nullable: true }) error: string | null - @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) + @OneToOne( + () => Transaction, + (transaction) => transaction.dltTransaction, + ) @JoinColumn({ name: 'transaction_id' }) transaction?: Transaction | null - @OneToOne(() => User, (user) => user.dltTransaction) + @OneToOne( + () => User, + (user) => user.dltTransaction, + ) @JoinColumn({ name: 'user_id' }) user?: User | null - @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.dltTransaction) + @OneToOne( + () => TransactionLink, + (transactionLink) => transactionLink.dltTransaction, + ) @JoinColumn({ name: 'transaction_link_id' }) transactionLink?: TransactionLink | null } diff --git a/database/src/entity/Event.ts b/database/src/entity/Event.ts index 9d17ffdeb..b5ed77b21 100644 --- a/database/src/entity/Event.ts +++ b/database/src/entity/Event.ts @@ -13,8 +13,8 @@ import { ContributionLink } from './ContributionLink' import { ContributionMessage } from './ContributionMessage' import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' -import { User } from './User' import { DecimalTransformer } from './transformer/DecimalTransformer' +import { User } from './User' @Entity('events') export class Event extends BaseEntity { diff --git a/database/src/entity/Transaction.ts b/database/src/entity/Transaction.ts index 6a6e13b5b..293b3af32 100644 --- a/database/src/entity/Transaction.ts +++ b/database/src/entity/Transaction.ts @@ -1,10 +1,18 @@ /* eslint-disable no-use-before-define */ import { Decimal } from 'decimal.js-light' -import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn } from 'typeorm' +import { + BaseEntity, + Column, + Entity, + JoinColumn, + ManyToOne, + OneToOne, + PrimaryGeneratedColumn, +} from 'typeorm' import { Contribution } from './Contribution' import { DltTransaction } from './DltTransaction' -import { DecimalTransformer } from './transformer/DecimalTransformer' import { TransactionLink } from './TransactionLink' +import { DecimalTransformer } from './transformer/DecimalTransformer' @Entity('transactions') export class Transaction extends BaseEntity { @@ -159,7 +167,10 @@ export class Transaction extends BaseEntity { @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) contribution?: Contribution | null - @OneToOne(() => DltTransaction, (dlt) => dlt.transactionId) + @OneToOne( + () => DltTransaction, + (dlt) => dlt.transactionId, + ) @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) dltTransaction?: DltTransaction | null @@ -167,7 +178,10 @@ export class Transaction extends BaseEntity { @JoinColumn({ name: 'previous' }) previousTransaction?: Transaction | null - @ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions) + @ManyToOne( + () => TransactionLink, + (transactionLink) => transactionLink.transactions, + ) @JoinColumn({ name: 'transaction_link_id' }) transactionLink?: TransactionLink | null } diff --git a/database/src/entity/TransactionLink.ts b/database/src/entity/TransactionLink.ts index f18c5acec..326573c16 100644 --- a/database/src/entity/TransactionLink.ts +++ b/database/src/entity/TransactionLink.ts @@ -1,9 +1,18 @@ import { Decimal } from 'decimal.js-light' -import { BaseEntity, Column, DeleteDateColumn, Entity, JoinColumn, OneToMany, OneToOne, PrimaryGeneratedColumn } from 'typeorm' -import { DecimalTransformer } from './transformer/DecimalTransformer' -import { User } from './User' +import { + BaseEntity, + Column, + DeleteDateColumn, + Entity, + JoinColumn, + OneToMany, + OneToOne, + PrimaryGeneratedColumn, +} from 'typeorm' import { DltTransaction } from './DltTransaction' import { Transaction } from './Transaction' +import { DecimalTransformer } from './transformer/DecimalTransformer' +import { User } from './User' @Entity('transaction_links') export class TransactionLink extends BaseEntity { @@ -62,15 +71,24 @@ export class TransactionLink extends BaseEntity { @Column({ type: 'int', unsigned: true, nullable: true }) redeemedBy: number | null - @OneToOne(() => DltTransaction, (dlt) => dlt.transactionLinkId) + @OneToOne( + () => DltTransaction, + (dlt) => dlt.transactionLinkId, + ) @JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' }) dltTransaction?: DltTransaction | null - @OneToOne(() => User, (user) => user.transactionLink) + @OneToOne( + () => User, + (user) => user.transactionLink, + ) @JoinColumn({ name: 'userId' }) user: User - @OneToMany(() => Transaction, (transaction) => transaction.transactionLink) + @OneToMany( + () => Transaction, + (transaction) => transaction.transactionLink, + ) @JoinColumn({ referencedColumnName: 'transaction_link_id' }) transactions: Transaction[] } diff --git a/database/src/entity/User.ts b/database/src/entity/User.ts index f438e8ac8..b2366b93c 100644 --- a/database/src/entity/User.ts +++ b/database/src/entity/User.ts @@ -13,11 +13,11 @@ import { import { Community } from './Community' import { Contribution } from './Contribution' import { ContributionMessage } from './ContributionMessage' -import { UserContact } from './UserContact' -import { UserRole } from './UserRole' -import { GeometryTransformer } from './transformer/GeometryTransformer' import { DltTransaction } from './DltTransaction' import { TransactionLink } from './TransactionLink' +import { GeometryTransformer } from './transformer/GeometryTransformer' +import { UserContact } from './UserContact' +import { UserRole } from './UserRole' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -216,11 +216,17 @@ export class User extends BaseEntity { @JoinColumn({ name: 'user_id' }) userContacts?: UserContact[] - @OneToOne(() => DltTransaction, (dlt) => dlt.userId) + @OneToOne( + () => DltTransaction, + (dlt) => dlt.userId, + ) @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) dltTransaction?: DltTransaction | null - @OneToOne(() => TransactionLink, (transactionLink) => transactionLink.userId) + @OneToOne( + () => TransactionLink, + (transactionLink) => transactionLink.userId, + ) @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) transactionLink?: TransactionLink | null } diff --git a/database/src/index.ts b/database/src/index.ts index 56dec24ee..72718cd94 100644 --- a/database/src/index.ts +++ b/database/src/index.ts @@ -58,7 +58,7 @@ export const entities = [ ] export { latestDbVersion } +export { AppDatabase } from './AppDatabase' export * from './logging' export * from './queries' export * from './util' -export { AppDatabase } from './AppDatabase' diff --git a/database/src/logging/AbstractLogging.view.ts b/database/src/logging/AbstractLogging.view.ts index 00fdd4703..7e1616c65 100644 --- a/database/src/logging/AbstractLogging.view.ts +++ b/database/src/logging/AbstractLogging.view.ts @@ -1,6 +1,5 @@ -import util from 'util' - import { Decimal } from 'decimal.js-light' +import util from 'util' export abstract class AbstractLoggingView { protected bufferStringFormat: BufferEncoding = 'hex' diff --git a/database/src/logging/PendingTransactionLogging.view.ts b/database/src/logging/PendingTransactionLogging.view.ts index fad2d8f56..20e08e662 100644 --- a/database/src/logging/PendingTransactionLogging.view.ts +++ b/database/src/logging/PendingTransactionLogging.view.ts @@ -1,7 +1,7 @@ +import { PendingTransactionState } from 'shared' import { PendingTransaction, Transaction } from '../entity' import { AbstractLoggingView } from './AbstractLogging.view' import { TransactionLoggingView } from './TransactionLogging.view' -import { PendingTransactionState } from 'shared' export class PendingTransactionLoggingView extends AbstractLoggingView { public constructor(private self: PendingTransaction) { diff --git a/database/src/logging/UserContactLogging.view.ts b/database/src/logging/UserContactLogging.view.ts index 4bd567cad..5230c4311 100644 --- a/database/src/logging/UserContactLogging.view.ts +++ b/database/src/logging/UserContactLogging.view.ts @@ -8,7 +8,10 @@ enum OptInType { } export class UserContactLoggingView extends AbstractLoggingView { - public constructor(private self: UserContact, private showUser = true) { + public constructor( + private self: UserContact, + private showUser = true, + ) { super() } @@ -16,9 +19,10 @@ export class UserContactLoggingView extends AbstractLoggingView { return { id: this.self.id, type: this.self.type, - user: this.showUser && this.self.user - ? new UserLoggingView(this.self.user).toJSON() - : { id: this.self.userId }, + user: + this.showUser && this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, email: this.self.email?.substring(0, 3) + '...', emailVerificationCode: this.self.emailVerificationCode?.substring(0, 4) + '...', emailOptInTypeId: OptInType[this.self.emailOptInTypeId], diff --git a/database/src/logging/UserLogging.view.ts b/database/src/logging/UserLogging.view.ts index 84db8a6fe..9d5f2bf92 100644 --- a/database/src/logging/UserLogging.view.ts +++ b/database/src/logging/UserLogging.view.ts @@ -1,10 +1,10 @@ import { User } from '../entity' import { AbstractLoggingView } from './AbstractLogging.view' +import { CommunityLoggingView } from './CommunityLogging.view' import { ContributionLoggingView } from './ContributionLogging.view' import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' import { UserContactLoggingView } from './UserContactLogging.view' import { UserRoleLoggingView } from './UserRoleLogging.view' -import { CommunityLoggingView } from './CommunityLogging.view' enum PasswordEncryptionType { NO_PASSWORD = 0, diff --git a/database/src/logging/UserRoleLogging.view.ts b/database/src/logging/UserRoleLogging.view.ts index ebfa3aed8..2d47bba19 100644 --- a/database/src/logging/UserRoleLogging.view.ts +++ b/database/src/logging/UserRoleLogging.view.ts @@ -3,16 +3,20 @@ import { AbstractLoggingView } from './AbstractLogging.view' import { UserLoggingView } from './UserLogging.view' export class UserRoleLoggingView extends AbstractLoggingView { - public constructor(private self: UserRole, private showUser = true) { + public constructor( + private self: UserRole, + private showUser = true, + ) { super() } public toJSON(): any { return { id: this.self.id, - user: this.showUser && this.self.user - ? new UserLoggingView(this.self.user).toJSON() - : { id: this.self.userId }, + user: + this.showUser && this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, role: this.self.role, createdAt: this.dateToString(this.self.createdAt), updatedAt: this.dateToString(this.self.updatedAt), diff --git a/database/src/queries/communities.test.ts b/database/src/queries/communities.test.ts index 18975256c..0655dba92 100644 --- a/database/src/queries/communities.test.ts +++ b/database/src/queries/communities.test.ts @@ -1,8 +1,8 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from '..' import { AppDatabase } from '../AppDatabase' -import { getHomeCommunity, getReachableCommunities } from './communities' -import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest' import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community' +import { getHomeCommunity, getReachableCommunities } from './communities' const db = AppDatabase.getInstance() @@ -39,7 +39,7 @@ describe('community.queries', () => { expect(community?.privateKey).toStrictEqual(homeCom.privateKey) }) }) - describe('getReachableCommunities', () => { + describe('getReachableCommunities', () => { it('home community counts also to reachable communities', async () => { await createCommunity(false) expect(await getReachableCommunities(1000)).toHaveLength(1) @@ -86,4 +86,4 @@ describe('community.queries', () => { expect(await getReachableCommunities(1000)).toHaveLength(0) }) }) -}) \ No newline at end of file +}) diff --git a/database/src/queries/communities.ts b/database/src/queries/communities.ts index e216f8af6..22c59314b 100644 --- a/database/src/queries/communities.ts +++ b/database/src/queries/communities.ts @@ -1,6 +1,6 @@ +import { urlSchema, uuidv4Schema } from 'shared' import { FindOptionsOrder, FindOptionsWhere, IsNull, MoreThanOrEqual, Not } from 'typeorm' import { Community as DbCommunity } from '../entity' -import { urlSchema, uuidv4Schema } from 'shared' /** * Retrieves the home community, i.e., a community that is not foreign. @@ -20,7 +20,9 @@ export async function getCommunityByUuid(communityUuid: string): Promise { +export function findWithCommunityIdentifier( + communityIdentifier: string, +): FindOptionsWhere { const where: FindOptionsWhere = {} // pre filter identifier type to reduce db query complexity if (urlSchema.safeParse(communityIdentifier).success) { @@ -42,22 +44,22 @@ export async function getCommunityWithFederatedCommunityByIdentifier( }) } -// returns all reachable communities +// returns all reachable communities // home community and all federated communities which have been verified within the last authenticationTimeoutMs export async function getReachableCommunities( authenticationTimeoutMs: number, - order?: FindOptionsOrder + order?: FindOptionsOrder, ): Promise { return await DbCommunity.find({ - where: [ - { - authenticatedAt: Not(IsNull()), - federatedCommunities: { - verifiedAt: MoreThanOrEqual(new Date(Date.now() - authenticationTimeoutMs)) - } + where: [ + { + authenticatedAt: Not(IsNull()), + federatedCommunities: { + verifiedAt: MoreThanOrEqual(new Date(Date.now() - authenticationTimeoutMs)), + }, }, { foreign: false }, ], order, }) -} \ No newline at end of file +} diff --git a/database/src/queries/events.ts b/database/src/queries/events.ts index ff0967944..2e954d4eb 100644 --- a/database/src/queries/events.ts +++ b/database/src/queries/events.ts @@ -1,19 +1,15 @@ -import { - ContributionLink as DbContributionLink, - Event as DbEvent, - User as DbUser -} from '../entity' +import { ContributionLink as DbContributionLink, Event as DbEvent, User as DbUser } from '../entity' -export async function findModeratorCreatingContributionLink(contributionLink: DbContributionLink): Promise { - const event = await DbEvent.findOne( - { - where: { - involvedContributionLinkId: contributionLink.id, - // todo: move event types into db - type: 'ADMIN_CONTRIBUTION_LINK_CREATE' - }, - relations: { actingUser: true } - } - ) +export async function findModeratorCreatingContributionLink( + contributionLink: DbContributionLink, +): Promise { + const event = await DbEvent.findOne({ + where: { + involvedContributionLinkId: contributionLink.id, + // todo: move event types into db + type: 'ADMIN_CONTRIBUTION_LINK_CREATE', + }, + relations: { actingUser: true }, + }) return event?.actingUser -} \ No newline at end of file +} diff --git a/database/src/queries/index.ts b/database/src/queries/index.ts index 54b5c6d4e..5fdc68c82 100644 --- a/database/src/queries/index.ts +++ b/database/src/queries/index.ts @@ -1,10 +1,10 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const' -export * from './user' export * from './communities' -export * from './pendingTransactions' -export * from './transactions' -export * from './transactionLinks' export * from './events' +export * from './pendingTransactions' +export * from './transactionLinks' +export * from './transactions' +export * from './user' export const LOG4JS_QUERIES_CATEGORY_NAME = `${LOG4JS_BASE_CATEGORY_NAME}.queries` diff --git a/database/src/queries/pendingTransactions.test.ts b/database/src/queries/pendingTransactions.test.ts index c59c312e4..1f7d0a3b7 100644 --- a/database/src/queries/pendingTransactions.test.ts +++ b/database/src/queries/pendingTransactions.test.ts @@ -1,22 +1,22 @@ -import { - PendingTransaction as DbPendingTransaction, - User as DbUser, - UserContact as DbUserContact, - Community as DbCommunity -} from '..' -import { countOpenPendingTransactions } from './pendingTransactions' +import Decimal from 'decimal.js-light' import { PendingTransactionState } from 'shared' +import { v4 as uuidv4 } from 'uuid' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import { + Community as DbCommunity, + PendingTransaction as DbPendingTransaction, + User as DbUser, + UserContact as DbUserContact, +} from '..' import { AppDatabase } from '../AppDatabase' -import { userFactory } from '../seeds/factory/user' +import { createCommunity } from '../seeds/community' import { pendingTransactionFactory } from '../seeds/factory/pendingTransaction' +import { userFactory } from '../seeds/factory/user' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' -import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' import { garrickOllivander } from '../seeds/users/garrick-ollivander' -import { describe, expect, it, beforeAll, afterAll } from 'vitest' -import { createCommunity } from '../seeds/community' -import { v4 as uuidv4 } from 'uuid' -import Decimal from 'decimal.js-light' +import { peterLustig } from '../seeds/users/peter-lustig' +import { countOpenPendingTransactions } from './pendingTransactions' const db = AppDatabase.getInstance() @@ -27,7 +27,6 @@ afterAll(async () => { await db.destroy() }) - describe('countOpenPendingTransactions', () => { let bibi: DbUser let peter: DbUser @@ -41,45 +40,44 @@ describe('countOpenPendingTransactions', () => { await createCommunity(false) - bibi = await userFactory(bibiBloxberg) + bibi = await userFactory(bibiBloxberg) peter = await userFactory(peterLustig) bob = await userFactory(bobBaumeister) garrick = await userFactory(garrickOllivander) // Bibi -> Peter await pendingTransactionFactory( - bibi, - peter, - new Decimal(10), - 'Bibi -> Peter new', - PendingTransactionState.NEW + bibi, + peter, + new Decimal(10), + 'Bibi -> Peter new', + PendingTransactionState.NEW, ) await pendingTransactionFactory( - bibi, - peter, - new Decimal(100.01), - 'Bibi -> Peter settled', - PendingTransactionState.SETTLED + bibi, + peter, + new Decimal(100.01), + 'Bibi -> Peter settled', + PendingTransactionState.SETTLED, ) // Peter -> Bibi await pendingTransactionFactory( - peter, - bibi, - new Decimal(12), - 'Peter -> Bibi new', - PendingTransactionState.NEW + peter, + bibi, + new Decimal(12), + 'Peter -> Bibi new', + PendingTransactionState.NEW, ) // Bob -> Peter await pendingTransactionFactory( - bob, - peter, - new Decimal(17.1), - 'Bob -> Peter new', - PendingTransactionState.NEW + bob, + peter, + new Decimal(17.1), + 'Bob -> Peter new', + PendingTransactionState.NEW, ) - }) it('should return 0 if called with empty array', async () => { const count = await countOpenPendingTransactions([]) @@ -104,21 +102,20 @@ describe('countOpenPendingTransactions', () => { it('peter and bob have one transaction together, peter two additional, should return 3', async () => { const count = await countOpenPendingTransactions([peter.gradidoID, bob.gradidoID]) expect(count).toBe(3) - }) - + }) + it('peter has three transactions, should return 3', async () => { const count = await countOpenPendingTransactions([peter.gradidoID]) expect(count).toBe(3) - }) - + }) it('bibi has two transactions, should return 2', async () => { const count = await countOpenPendingTransactions([bibi.gradidoID]) expect(count).toBe(2) - }) + }) it('bob has one transaction, should return 1', async () => { const count = await countOpenPendingTransactions([bob.gradidoID]) expect(count).toBe(1) - }) + }) }) diff --git a/database/src/queries/pendingTransactions.ts b/database/src/queries/pendingTransactions.ts index 44bf63f82..b6481af33 100644 --- a/database/src/queries/pendingTransactions.ts +++ b/database/src/queries/pendingTransactions.ts @@ -1,6 +1,6 @@ -import { PendingTransaction as DbPendingTransaction } from '../entity' -import { In } from 'typeorm' import { PendingTransactionState } from 'shared' +import { In } from 'typeorm' +import { PendingTransaction as DbPendingTransaction } from '../entity' /** * Counts the number of open pending transactions for the given users. @@ -15,4 +15,4 @@ export async function countOpenPendingTransactions(users: string[]): Promise { return await DbTransactionLink.findOneOrFail({ diff --git a/database/src/queries/user.test.ts b/database/src/queries/user.test.ts index 873ca7a2b..57096d264 100644 --- a/database/src/queries/user.test.ts +++ b/database/src/queries/user.test.ts @@ -1,14 +1,14 @@ -import { User as DbUser, UserContact as DbUserContact, Community as DbCommunity } from '..' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' +import { clearLogs, getLogger, printLogs } from '../../../config-schema/test/testSetup.vitest' +import { Community as DbCommunity, User as DbUser, UserContact as DbUserContact } from '..' import { AppDatabase } from '../AppDatabase' -import { aliasExists, findUserByIdentifier } from './user' +import { createCommunity } from '../seeds/community' import { userFactory } from '../seeds/factory/user' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' -import { describe, expect, it, beforeAll, afterAll, beforeEach, } from 'vitest' -import { createCommunity } from '../seeds/community' -import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' -import { getLogger, printLogs, clearLogs } from '../../../config-schema/test/testSetup.vitest' +import { peterLustig } from '../seeds/users/peter-lustig' import { LOG4JS_QUERIES_CATEGORY_NAME } from '.' +import { aliasExists, findUserByIdentifier } from './user' const db = AppDatabase.getInstance() const userIdentifierLoggerName = `${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier` @@ -26,9 +26,9 @@ describe('user.queries', () => { await DbUser.clear() await DbUserContact.clear() - const bibi = bibiBloxberg + const bibi = bibiBloxberg bibi.alias = 'b-b' - await userFactory(bibi) + await userFactory(bibi) }) it('should return true if alias exists', async () => { @@ -70,12 +70,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityUuid) expect(user).toMatchObject(userBibi) @@ -85,18 +85,18 @@ describe('user.queries', () => { expect(user).toBeNull() }) }) - + describe('communityIdentifier is community name', () => { it('userIdentifier is gradido id', async () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityName) expect(user).toMatchObject(userBibi) @@ -117,12 +117,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email) expect(user).toMatchObject(userBibi) @@ -130,11 +130,12 @@ describe('user.queries', () => { it('userIdentifier is unknown type', async () => { const user = await findUserByIdentifier('sa') printLogs() - expect(getLogger(userIdentifierLoggerName).warn).toHaveBeenCalledWith('Unknown identifier type', 'sa') + expect(getLogger(userIdentifierLoggerName).warn).toHaveBeenCalledWith( + 'Unknown identifier type', + 'sa', + ) expect(user).toBeNull() }) - }) + }) }) -}) - - +}) diff --git a/database/src/queries/user.ts b/database/src/queries/user.ts index d42bd689c..9e7d84c27 100644 --- a/database/src/queries/user.ts +++ b/database/src/queries/user.ts @@ -1,7 +1,7 @@ +import { getLogger } from 'log4js' +import { aliasSchema, emailSchema, uuidv4Schema } from 'shared' import { Raw } from 'typeorm' import { User as DbUser, UserContact as DbUserContact } from '../entity' -import { aliasSchema, emailSchema, uuidv4Schema } from 'shared' -import { getLogger } from 'log4js' import { findWithCommunityIdentifier, LOG4JS_QUERIES_CATEGORY_NAME } from './index' export async function aliasExists(alias: string): Promise { @@ -11,7 +11,11 @@ export async function aliasExists(alias: string): Promise { return user !== null } -export async function getUserById(id: number, withCommunity: boolean = false, withEmailContact: boolean = false): Promise { +export async function getUserById( + id: number, + withCommunity: boolean = false, + withEmailContact: boolean = false, +): Promise { return DbUser.findOneOrFail({ where: { id }, relations: { community: withCommunity, emailContact: withEmailContact }, @@ -28,8 +32,8 @@ export const findUserByIdentifier = async ( identifier: string, communityIdentifier?: string, ): Promise => { - const communityWhere = communityIdentifier - ? findWithCommunityIdentifier(communityIdentifier) + const communityWhere = communityIdentifier + ? findWithCommunityIdentifier(communityIdentifier) : undefined if (uuidv4Schema.safeParse(identifier).success) { @@ -48,12 +52,12 @@ export const findUserByIdentifier = async ( }, relations: { user: { community: true } }, }) - if (userContact) { + if (userContact) { // TODO: remove circular reference const user = userContact.user user.emailContact = userContact return user - } + } } else if (aliasSchema.safeParse(identifier).success) { return await DbUser.findOne({ where: { alias: identifier, community: communityWhere }, @@ -61,7 +65,10 @@ export const findUserByIdentifier = async ( }) } else { // should don't happen often, so we create only in the rare case a logger for it - getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn('Unknown identifier type', identifier) + getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn( + 'Unknown identifier type', + identifier, + ) } return null } diff --git a/database/src/seeds/community.ts b/database/src/seeds/community.ts index 4db872398..6260583dd 100644 --- a/database/src/seeds/community.ts +++ b/database/src/seeds/community.ts @@ -1,42 +1,42 @@ -import { Community, FederatedCommunity } from '../entity' import { randomBytes } from 'node:crypto' import { v4 as uuidv4 } from 'uuid' +import { Community, FederatedCommunity } from '../entity' export async function createCommunity(foreign: boolean, save: boolean = true): Promise { - const community = new Community() - community.publicKey = randomBytes(32) - community.communityUuid = uuidv4() - community.name = 'HomeCommunity-name' - community.creationDate = new Date() + const community = new Community() + community.publicKey = randomBytes(32) + community.communityUuid = uuidv4() + community.name = 'HomeCommunity-name' + community.creationDate = new Date() - if(foreign) { - community.foreign = true - community.name = 'ForeignCommunity-name' - community.description = 'ForeignCommunity-description' - community.url = `http://foreign-${Math.random()}/api` - community.authenticatedAt = new Date() - } else { - community.foreign = false - // todo: generate valid public/private key pair (ed25519) - community.privateKey = randomBytes(64) - community.name = 'HomeCommunity-name' - community.description = 'HomeCommunity-description' - community.url = 'http://localhost/api' - } - return save ? await community.save() : community + if (foreign) { + community.foreign = true + community.name = 'ForeignCommunity-name' + community.description = 'ForeignCommunity-description' + community.url = `http://foreign-${Math.random()}/api` + community.authenticatedAt = new Date() + } else { + community.foreign = false + // todo: generate valid public/private key pair (ed25519) + community.privateKey = randomBytes(64) + community.name = 'HomeCommunity-name' + community.description = 'HomeCommunity-description' + community.url = 'http://localhost/api' + } + return save ? await community.save() : community } export async function createVerifiedFederatedCommunity( - apiVersion: string, - verifiedBeforeMs: number, - community: Community, - save: boolean = true + apiVersion: string, + verifiedBeforeMs: number, + community: Community, + save: boolean = true, ): Promise { - const federatedCommunity = new FederatedCommunity() - federatedCommunity.apiVersion = apiVersion - federatedCommunity.endPoint = community.url - federatedCommunity.publicKey = community.publicKey - federatedCommunity.community = community - federatedCommunity.verifiedAt = new Date(Date.now() - verifiedBeforeMs) - return save ? await federatedCommunity.save() : federatedCommunity + const federatedCommunity = new FederatedCommunity() + federatedCommunity.apiVersion = apiVersion + federatedCommunity.endPoint = community.url + federatedCommunity.publicKey = community.publicKey + federatedCommunity.community = community + federatedCommunity.verifiedAt = new Date(Date.now() - verifiedBeforeMs) + return save ? await federatedCommunity.save() : federatedCommunity } diff --git a/database/src/seeds/factory/pendingTransaction.ts b/database/src/seeds/factory/pendingTransaction.ts index 2e8c7d256..75cb7c70e 100644 --- a/database/src/seeds/factory/pendingTransaction.ts +++ b/database/src/seeds/factory/pendingTransaction.ts @@ -1,6 +1,6 @@ -import { User as DbUser, PendingTransaction as DbPendingTransaction } from '../..' -import { PendingTransactionState } from 'shared' import { Decimal } from 'decimal.js-light' +import { PendingTransactionState } from 'shared' +import { PendingTransaction as DbPendingTransaction, User as DbUser } from '../..' export async function pendingTransactionFactory( sender: DbUser, @@ -17,7 +17,7 @@ export async function pendingTransactionFactory( pendingTransaction.userGradidoID = sender.gradidoID pendingTransaction.userCommunityUuid = sender.communityUuid! pendingTransaction.linkedUserId = receiver.id - pendingTransaction.linkedUserGradidoID = receiver.gradidoID - pendingTransaction.linkedUserCommunityUuid = receiver.communityUuid! + pendingTransaction.linkedUserGradidoID = receiver.gradidoID + pendingTransaction.linkedUserCommunityUuid = receiver.communityUuid! await pendingTransaction.save() } diff --git a/database/src/seeds/factory/user.ts b/database/src/seeds/factory/user.ts index 3772fe66d..912cf00d0 100644 --- a/database/src/seeds/factory/user.ts +++ b/database/src/seeds/factory/user.ts @@ -1,16 +1,16 @@ -import { UserInterface } from '../users/UserInterface' -import { User, UserContact } from '../../entity' -import { v4 } from 'uuid' -import { UserContactType, OptInType, PasswordEncryptionType } from 'shared' -import { getHomeCommunity } from '../../queries/communities' import random from 'crypto-random-bigint' +import { OptInType, PasswordEncryptionType, UserContactType } from 'shared' +import { v4 } from 'uuid' +import { User, UserContact } from '../../entity' +import { getHomeCommunity } from '../../queries/communities' +import { UserInterface } from '../users/UserInterface' export const userFactory = async (user: UserInterface): Promise => { let dbUserContact = new UserContact() dbUserContact.email = user.email ?? '' dbUserContact.type = UserContactType.USER_CONTACT_EMAIL - + let dbUser = new User() dbUser.firstName = user.firstName ?? '' dbUser.lastName = user.lastName ?? '' @@ -35,11 +35,11 @@ export const userFactory = async (user: UserInterface): Promise => { dbUser.community = homeCommunity dbUser.communityUuid = homeCommunity.communityUuid! } - // TODO: improve with cascade + // TODO: improve with cascade dbUser = await dbUser.save() dbUserContact.userId = dbUser.id dbUserContact = await dbUserContact.save() dbUser.emailId = dbUserContact.id dbUser.emailContact = dbUserContact return dbUser.save() -} \ No newline at end of file +} diff --git a/database/src/seeds/users/peter-lustig.ts b/database/src/seeds/users/peter-lustig.ts index 58b07fe99..ebd5235af 100644 --- a/database/src/seeds/users/peter-lustig.ts +++ b/database/src/seeds/users/peter-lustig.ts @@ -7,5 +7,5 @@ export const peterLustig: UserInterface = { // description: 'Latzhose und Nickelbrille', createdAt: new Date('2020-11-25T10:48:43'), emailChecked: true, - language: 'de' + language: 'de', } diff --git a/database/src/util/index.ts b/database/src/util/index.ts index d2fde2126..e2eb6c04e 100644 --- a/database/src/util/index.ts +++ b/database/src/util/index.ts @@ -1,2 +1,2 @@ -export * from './TRANSACTIONS_LOCK' export * from './TRANSACTION_LINK_LOCK' +export * from './TRANSACTIONS_LOCK' diff --git a/package.json b/package.json index 464aa991b..e3cf8fb82 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "uuid": "^8.3.2" }, "devDependencies": { - "@biomejs/biome": "2.0.0" + "@biomejs/biome": "^2.2.5" }, "engines": { "node": ">=18" diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 75b686340..298ef9475 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -47,7 +47,11 @@ // "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [".", "../database"], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ + "typeRoots": [ /* List of folders to include type definitions from. */ + "@types", + "node_modules/@types", + "../node_modules/@types" + ], /* List of folders to include type definitions from. */ // "types": ["bun-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'. */ diff --git a/yarn.lock b/yarn.lock index 2b815e0ef..c5cf10a37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -400,46 +400,100 @@ "@biomejs/cli-win32-arm64" "2.0.0" "@biomejs/cli-win32-x64" "2.0.0" +"@biomejs/biome@^2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.2.5.tgz#291df1137404843537dd50eaa0174c12c0681d82" + integrity sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "2.2.5" + "@biomejs/cli-darwin-x64" "2.2.5" + "@biomejs/cli-linux-arm64" "2.2.5" + "@biomejs/cli-linux-arm64-musl" "2.2.5" + "@biomejs/cli-linux-x64" "2.2.5" + "@biomejs/cli-linux-x64-musl" "2.2.5" + "@biomejs/cli-win32-arm64" "2.2.5" + "@biomejs/cli-win32-x64" "2.2.5" + "@biomejs/cli-darwin-arm64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.0.0.tgz#67135faa8bd52933fdaad09a160f9fc3a9defef3" integrity sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw== +"@biomejs/cli-darwin-arm64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.5.tgz#2a181f4b0daef11e24b96eaac9dd7866125b2524" + integrity sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ== + "@biomejs/cli-darwin-x64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.0.0.tgz#49a7e064bad53e095d8a152b072adffcdeb4fb8e" integrity sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw== +"@biomejs/cli-darwin-x64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.5.tgz#0ecfa984d8b76dda4771b95cf1d796d79c257a18" + integrity sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg== + "@biomejs/cli-linux-arm64-musl@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.0.tgz#bfde27de8262a20e57e153f3807f47a01ccaeab3" integrity sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA== +"@biomejs/cli-linux-arm64-musl@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.5.tgz#264e632302e61c0b34c13d3d92b6f9b8fb5e1e97" + integrity sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw== + "@biomejs/cli-linux-arm64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.0.0.tgz#c2404b3869c03a6fa5a8b979755bc6dfd5a5ec47" integrity sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw== +"@biomejs/cli-linux-arm64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.5.tgz#acc71fb62fb6d022766042fb004da47439bd1b24" + integrity sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ== + "@biomejs/cli-linux-x64-musl@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.0.tgz#8ab214ac7e21a2af29435439145888c50f2bdd2f" integrity sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA== +"@biomejs/cli-linux-x64-musl@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.5.tgz#03df0646ed4e26631ef3e1fcb4fc527e45345b86" + integrity sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ== + "@biomejs/cli-linux-x64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.0.0.tgz#cbd172ead9e5bba8cd590d06e6e548445cf7ab2a" integrity sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg== +"@biomejs/cli-linux-x64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.5.tgz#2740f260da9518554219ed07729ec0fdd8104135" + integrity sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew== + "@biomejs/cli-win32-arm64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.0.0.tgz#4677f4e034b3f4906e448b704f3314b38062a111" integrity sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw== +"@biomejs/cli-win32-arm64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.5.tgz#75db880f3bb6c481435f0f602093b1ced9b2327e" + integrity sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg== + "@biomejs/cli-win32-x64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.0.0.tgz#f460a6950235c8f4bbd4cc405b210fec5cdb8ac9" integrity sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg== +"@biomejs/cli-win32-x64@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.5.tgz#f0f3a85c5fb7954661fe454ef2df998205df1570" + integrity sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" @@ -2383,10 +2437,10 @@ dependencies: dotenv "*" -"@types/email-templates@^10.0.4": - version "10.0.4" - resolved "https://registry.npmjs.org/@types/email-templates/-/email-templates-10.0.4.tgz" - integrity sha512-8O2bdGPO6RYgH2DrnFAcuV++s+8KNA5e2Erjl6UxgKRVsBH9zXu2YLrLyOBRMn2VyEYmzgF+6QQUslpVhj0y/g== +"@types/email-templates@10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@types/email-templates/-/email-templates-10.0.1.tgz#88f218564a6341092f447fbe110047f6bf3e955a" + integrity sha512-IHdgtoOUfMB4t5y5wgm8G0i2/U90GeJPxIEAViMaLlJPCJzaYSlVHXI8bx3qbgbD6gxyOsSRyrFvBSTgNEQc+g== dependencies: "@types/html-to-text" "*" "@types/nodemailer" "*" @@ -2691,7 +2745,7 @@ dependencies: undici-types "~5.26.4" -"@types/nodemailer@*", "@types/nodemailer@^6.4.4": +"@types/nodemailer@*", "@types/nodemailer@6.4.17": version "6.4.17" resolved "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz" integrity sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww== @@ -5459,9 +5513,9 @@ electron-to-chromium@^1.5.73: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.144.tgz" integrity sha512-eJIaMRKeAzxfBSxtjYnoIAw/tdD6VIH6tHBZepZnAbE3Gyqqs5mGN87DvcldPUbVkIljTK8pY0CMcUljP64lfQ== -email-templates@^10.0.1: +email-templates@10.0.1: version "10.0.1" - resolved "https://registry.npmjs.org/email-templates/-/email-templates-10.0.1.tgz" + resolved "https://registry.yarnpkg.com/email-templates/-/email-templates-10.0.1.tgz#00ed3d394c3b64fa7b8127027e52b01d70c468d4" integrity sha512-LNZKS0WW9XQkjuDZd/4p/1Q/pwqaqXOP3iDxTIVIQY9vuHlIUEcRLFo8/Xh3GtZCBnm181VgvOXIABKTVyTePA== dependencies: "@ladjs/i18n" "^8.0.1" @@ -9147,12 +9201,17 @@ node-releases@^2.0.19: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== +nodemailer@6.6.5: + version "6.6.5" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.5.tgz#f9f6953cee5cfe82cbea152eeddacf7a0442049a" + integrity sha512-C/v856DBijUzHcHIgGpQoTrfsH3suKIRAGliIzCstatM2cAa+MYX3LuyCrABiO/cdJTxgBBHXxV1ztiqUwst5A== + nodemailer@6.9.16: version "6.9.16" resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz" integrity sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ== -nodemailer@^6.6.5, nodemailer@^6.7.7, nodemailer@^6.9.13: +nodemailer@^6.7.7, nodemailer@^6.9.13: version "6.10.1" resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz" integrity sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA== From a782e3610a18a0219aa46c48714ff58f1ccdaadb Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 9 Oct 2025 13:19:55 +0200 Subject: [PATCH 041/226] fix tests --- backend/package.json | 8 ++-- .../dltConnector/DltConnectorClient.test.ts | 2 +- .../resolver/TransactionResolver.test.ts | 44 ------------------- .../src/graphql/resolver/semaphore.test.ts | 3 ++ bun.lock | 32 ++++++-------- dht-node/.env.dist | 2 +- 6 files changed, 23 insertions(+), 68 deletions(-) diff --git a/backend/package.json b/backend/package.json index 89e0f22b5..554e166ae 100644 --- a/backend/package.json +++ b/backend/package.json @@ -32,7 +32,7 @@ }, "dependencies": { "cross-env": "^7.0.3", - "email-templates": "10.0.1", + "email-templates": "^10.0.1", "sodium-native": "^3.4.1" }, "devDependencies": { @@ -41,14 +41,14 @@ "@swc/cli": "^0.7.3", "@swc/core": "^1.11.24", "@swc/helpers": "^0.5.17", - "@types/email-templates": "10.0.1", + "@types/email-templates": "^10.0.4", "@types/express": "^4.17.21", "@types/faker": "^5.5.9", "@types/i18n": "^0.13.4", "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "6.4.17", + "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -82,7 +82,7 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "6.6.5", + "nodemailer": "^6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index 0e2043a09..e3673791b 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -4,7 +4,7 @@ import { DltConnectorClient } from './DltConnectorClient' describe('undefined DltConnectorClient', () => { it('invalid url', () => { - CONFIG.DLT_CONNECTOR_URL = 'invalid' + CONFIG.DLT_CONNECTOR_URL = '' CONFIG.DLT_CONNECTOR = true const result = DltConnectorClient.getInstance() expect(result).toBeUndefined() diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index c6cc69250..a134ca84b 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -437,50 +437,6 @@ describe('send coins', () => { }), ) }) - - describe('sendTransactionsToDltConnector', () => { - let transaction: Transaction[] - let dltTransactions: DltTransaction[] - beforeAll(async () => { - // Find the previous created transactions of sendCoin mutation - transaction = await Transaction.find({ - where: { memo: 'unrepeatable memo' }, - order: { balanceDate: 'ASC', id: 'ASC' }, - }) - - // and read aslong as all async created dlt-transactions are finished - do { - dltTransactions = await DltTransaction.find({ - where: { transactionId: In([transaction[0].id, transaction[1].id]) }, - // relations: ['transaction'], - // order: { createdAt: 'ASC', id: 'ASC' }, - }) - } while (transaction.length > dltTransactions.length) - }) - - it('has wait till sendTransactionsToDltConnector created all dlt-transactions', () => { - expect(dltTransactions).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - transactionId: transaction[0].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - expect.objectContaining({ - id: expect.any(Number), - transactionId: transaction[1].id, - messageId: null, - verified: false, - createdAt: expect.any(Date), - verifiedAt: null, - }), - ]), - ) - }) - }) }) describe('send coins via gradido ID', () => { it('sends the coins', async () => { diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 3917efd31..9b4ec07df 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -21,9 +21,12 @@ import { import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' +import { CONFIG } from '@/config' jest.mock('@/password/EncryptorUtils') +CONFIG.DLT_CONNECTOR = false + let mutate: ApolloServerTestClient['mutate'] let con: DataSource let testEnv: { diff --git a/bun.lock b/bun.lock index ed59d73cb..9b8884678 100644 --- a/bun.lock +++ b/bun.lock @@ -89,7 +89,7 @@ "version": "2.6.1", "dependencies": { "cross-env": "^7.0.3", - "email-templates": "10.0.1", + "email-templates": "^10.0.1", "sodium-native": "^3.4.1", }, "devDependencies": { @@ -98,14 +98,14 @@ "@swc/cli": "^0.7.3", "@swc/core": "^1.11.24", "@swc/helpers": "^0.5.17", - "@types/email-templates": "10.0.1", + "@types/email-templates": "^10.0.4", "@types/express": "^4.17.21", "@types/faker": "^5.5.9", "@types/i18n": "^0.13.4", "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "6.4.17", + "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -139,7 +139,7 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "6.6.5", + "nodemailer": "^6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", @@ -1063,7 +1063,7 @@ "@types/dotenv": ["@types/dotenv@8.2.3", "", { "dependencies": { "dotenv": "*" } }, "sha512-g2FXjlDX/cYuc5CiQvyU/6kkbP1JtmGzh0obW50zD7OKeILVL0NSpPWLXVfqoAGQjom2/SLLx9zHq0KXvD6mbw=="], - "@types/email-templates": ["@types/email-templates@10.0.1", "", { "dependencies": { "@types/html-to-text": "*", "@types/nodemailer": "*", "juice": "^8.0.0" } }, "sha512-IHdgtoOUfMB4t5y5wgm8G0i2/U90GeJPxIEAViMaLlJPCJzaYSlVHXI8bx3qbgbD6gxyOsSRyrFvBSTgNEQc+g=="], + "@types/email-templates": ["@types/email-templates@10.0.4", "", { "dependencies": { "@types/html-to-text": "*", "@types/nodemailer": "*", "juice": "^8.0.0" } }, "sha512-8O2bdGPO6RYgH2DrnFAcuV++s+8KNA5e2Erjl6UxgKRVsBH9zXu2YLrLyOBRMn2VyEYmzgF+6QQUslpVhj0y/g=="], "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], @@ -1631,7 +1631,7 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -2629,7 +2629,7 @@ "node-releases": ["node-releases@2.0.23", "", {}, "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg=="], - "nodemailer": ["nodemailer@6.6.5", "", {}, "sha512-C/v856DBijUzHcHIgGpQoTrfsH3suKIRAGliIzCstatM2cAa+MYX3LuyCrABiO/cdJTxgBBHXxV1ztiqUwst5A=="], + "nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], "nodemon": ["nodemon@2.0.22", "", { "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" } }, "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ=="], @@ -2671,7 +2671,7 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -3491,8 +3491,6 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -3575,20 +3573,22 @@ "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "@jest/transform/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], "@jest/types/@types/node": ["@types/node@18.19.129", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A=="], + "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "@morev/utils/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@nuxt/kit/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "@nuxt/kit/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -3733,8 +3733,6 @@ "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "c12/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -3793,8 +3791,6 @@ "editorconfig/minimatch": ["minimatch@9.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w=="], - "email-templates/nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], - "escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "eslint/@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "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" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], @@ -3977,8 +3973,6 @@ "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "preview-email/nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], - "preview-email/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -4093,6 +4087,8 @@ "unplugin-vue-components/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], diff --git a/dht-node/.env.dist b/dht-node/.env.dist index 351bc251d..1f4fca697 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -13,7 +13,7 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log # Federation # if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic FEDERATION_DHT_TOPIC=GRADIDO_HUB -# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f +FEDERATION_DHT_SEED=64ebcb0e3ad547848fed4197c6e1332f FEDERATION_COMMUNITY_URL=http://localhost # comma separated values, which apis should be announced FEDERATION_COMMUNITY_APIS=1_0 \ No newline at end of file From cced5644911167d12709bd07f45904587dfe227d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 9 Oct 2025 13:24:40 +0200 Subject: [PATCH 042/226] missing save --- backend/src/graphql/resolver/UserResolver.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 56e3b039b..2398a3a95 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -25,7 +25,7 @@ import { Root, } from 'type-graphql' import { IRestResponse } from 'typed-rest-client' -import { EntityManager, EntityNotFoundError, In, Point } from 'typeorm' +import { EntityNotFoundError, In, Point } from 'typeorm' import { v4 as uuidv4 } from 'uuid' import { UserArgs } from '@arg//UserArgs' @@ -104,11 +104,8 @@ import { deleteUserRole, setUserRole } from './util/modifyUserRole' import { sendUserToGms } from './util/sendUserToGms' import { syncHumhub } from './util/syncHumhub' import { validateAlias } from 'core' -<<<<<<< HEAD import { registerAddressTransaction } from '@/apis/dltConnector' -======= import { updateAllDefinedAndChanged } from 'shared' ->>>>>>> master const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl'] const DEFAULT_LANGUAGE = 'de' From 4548b1354b71372e7124e5a3cf351111966c48c7 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 20 Oct 2025 15:56:18 +0200 Subject: [PATCH 043/226] remove unused code --- dlt-connector/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 835a1cef5..95f0068ce 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -140,7 +140,4 @@ main().catch((e) => { console.error(e) process.exit(1) }) -function exitHook(arg0: () => void) { - throw new Error('Function not implemented.') -} From 4658f33b88c6dc423cff5eaa65253e108691f6ab Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 21 Oct 2025 08:19:09 +0200 Subject: [PATCH 044/226] fix backend test --- .../resolver/TransactionLinkResolver.ts | 2 +- .../graphql/resolver/TransactionResolver.ts | 5 +-- .../src/graphql/resolver/semaphore.test.ts | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 3756d3bd9..869104bae 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -396,8 +396,8 @@ export class TransactionLinkResolver { } return true } else { + const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() const now = new Date() - const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() try { const transactionLink = await DbTransactionLink.findOne({ where: { code } }) if (!transactionLink) { diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 505438f6a..0bd77166c 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -58,6 +58,8 @@ export const executeTransaction = async ( logger: Logger, transactionLink?: dbTransactionLink | null, ): Promise => { + // acquire lock + const releaseLock = await TRANSACTIONS_LOCK.acquire() const receivedCallDate = new Date() let dltTransactionPromise: Promise = Promise.resolve(null) if (!transactionLink) { @@ -66,9 +68,6 @@ export const executeTransaction = async ( dltTransactionPromise = redeemDeferredTransferTransaction(transactionLink, amount.toString(), receivedCallDate, recipient) } - // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() - try { logger.info('executeTransaction', memo) diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 9b4ec07df..d0bf08b7c 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -22,10 +22,12 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { CONFIG } from '@/config' +import { TRANSACTIONS_LOCK } from 'database' jest.mock('@/password/EncryptorUtils') CONFIG.DLT_CONNECTOR = false +CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] let con: DataSource @@ -47,7 +49,43 @@ afterAll(async () => { await con.destroy() }) +type RunOrder = { [key: number]: { start: number, end: number } } +async function fakeWork(runOrder: RunOrder, index: number) { + const releaseLock = await TRANSACTIONS_LOCK.acquire() + const startDate = new Date() + await new Promise((resolve) => setTimeout(resolve, Math.random() * 50)) + const endDate = new Date() + runOrder[index] = { start: startDate.getTime(), end: endDate.getTime() } + releaseLock() +} + describe('semaphore', () => { + it("didn't should run in parallel", async () => { + const runOrder: RunOrder = {} + await Promise.all([ + fakeWork(runOrder, 1), + fakeWork(runOrder, 2), + fakeWork(runOrder, 3), + fakeWork(runOrder, 4), + fakeWork(runOrder, 5), + ]) + expect(runOrder[1].start).toBeLessThan(runOrder[1].end) + expect(runOrder[1].start).toBeLessThan(runOrder[2].start) + expect(runOrder[2].start).toBeLessThan(runOrder[2].end) + expect(runOrder[2].start).toBeLessThan(runOrder[3].start) + expect(runOrder[3].start).toBeLessThan(runOrder[3].end) + expect(runOrder[3].start).toBeLessThan(runOrder[4].start) + expect(runOrder[4].start).toBeLessThan(runOrder[4].end) + expect(runOrder[4].start).toBeLessThan(runOrder[5].start) + expect(runOrder[5].start).toBeLessThan(runOrder[5].end) + expect(runOrder[1].end).toBeLessThan(runOrder[2].end) + expect(runOrder[2].end).toBeLessThan(runOrder[3].end) + expect(runOrder[3].end).toBeLessThan(runOrder[4].end) + expect(runOrder[4].end).toBeLessThan(runOrder[5].end) + }) +}) + +describe('semaphore fullstack', () => { let contributionLinkCode = '' let bobsTransactionLinkCode = '' let bibisTransactionLinkCode = '' From ed94bb7ea0dd2ece9a6f4947fe3db5be25913308 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 21 Oct 2025 11:56:31 +0200 Subject: [PATCH 045/226] fix test, refactor --- .../client/GradidoNode/input.schema.test.ts | 8 +- .../src/client/GradidoNode/input.schema.ts | 4 +- dlt-connector/src/client/hiero/HieroClient.ts | 56 ++++--- dlt-connector/src/config/index.ts | 12 +- .../src/data/KeyPairIdentifier.logic.ts | 75 +++++---- dlt-connector/src/errors.ts | 7 + dlt-connector/src/index.ts | 18 +-- .../KeyPairCalculation.context.test.ts | 99 ------------ .../KeyPairCalculation.context.ts | 54 ------- .../AbstractKeyPair.role.ts | 0 .../AbstractRemoteKeyPair.role.ts | 0 .../AccountKeyPair.role.ts | 0 .../ForeignCommunityKeyPair.role.ts | 0 .../HomeCommunityKeyPair.role.ts | 0 .../LinkedTransactionKeyPair.role.ts | 0 .../RemoteAccountKeyPair.role.ts | 0 .../ResolveKeyPair.context.test.ts | 84 ++++++++++ .../resolveKeyPair/ResolveKeyPair.context.ts | 81 ++++++++++ .../UserKeyPair.role.ts | 0 .../UserKeyPairRole.test.ts | 0 .../CommunityRootTransaction.role.ts | 4 +- .../sendToHiero/CreationTransaction.role.ts | 15 +- .../DeferredTransferTransaction.role.ts | 9 +- .../RedeemDeferredTransferTransaction.role.ts | 6 +- .../RegisterAddressTransaction.role.test.ts | 38 +++-- .../RegisterAddressTransaction.role.ts | 10 +- .../sendToHiero/SendToHiero.context.ts | 144 ++++++++++------- .../sendToHiero/TransferTransaction.role.ts | 6 +- dlt-connector/src/schemas/account.schema.ts | 9 +- .../src/schemas/transaction.schema.test.ts | 25 +-- .../src/schemas/transaction.schema.ts | 9 +- .../src/schemas/typeConverter.schema.test.ts | 54 ++++--- dlt-connector/src/schemas/typeGuard.schema.ts | 67 ++++---- dlt-connector/src/server/index.test.ts | 39 +++-- dlt-connector/src/server/index.ts | 147 ++++++++++++------ dlt-connector/src/server/input.schema.ts | 6 +- 36 files changed, 617 insertions(+), 469 deletions(-) delete mode 100644 dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts delete mode 100644 dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/AbstractKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/AbstractRemoteKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/AccountKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/ForeignCommunityKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/HomeCommunityKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/LinkedTransactionKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/RemoteAccountKeyPair.role.ts (100%) create mode 100644 dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts create mode 100644 dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/UserKeyPair.role.ts (100%) rename dlt-connector/src/interactions/{keyPairCalculation => resolveKeyPair}/UserKeyPairRole.test.ts (100%) diff --git a/dlt-connector/src/client/GradidoNode/input.schema.test.ts b/dlt-connector/src/client/GradidoNode/input.schema.test.ts index 1268290fc..b4c86326e 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.test.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.test.ts @@ -2,18 +2,18 @@ import { beforeAll, describe, expect, it } from 'bun:test' import { parse } from 'valibot' import { HieroId, - HieroTransactionId, + HieroTransactionIdString, hieroIdSchema, - hieroTransactionIdSchema, + hieroTransactionIdStringSchema, } from '../../schemas/typeGuard.schema' import { transactionIdentifierSchema } from './input.schema' let topic: HieroId const topicString = '0.0.261' -let hieroTransactionId: HieroTransactionId +let hieroTransactionId: HieroTransactionIdString beforeAll(() => { topic = parse(hieroIdSchema, topicString) - hieroTransactionId = parse(hieroTransactionIdSchema, '0.0.261-1755348116-1281621') + hieroTransactionId = parse(hieroTransactionIdStringSchema, '0.0.261-1755348116-1281621') }) describe('transactionIdentifierSchema ', () => { diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts index baa075baf..16a8643f5 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -1,5 +1,5 @@ import * as v from 'valibot' -import { hieroIdSchema, hieroTransactionIdSchema } from '../../schemas/typeGuard.schema' +import { hieroIdSchema, hieroTransactionIdStringSchema } from '../../schemas/typeGuard.schema' export const transactionsRangeSchema = v.object({ // default value is 1, from first transactions @@ -18,7 +18,7 @@ export const transactionIdentifierSchema = v.pipe( v.pipe(v.number('expect number type'), v.minValue(1, 'expect number >= 1')), undefined, ), - hieroTransactionId: v.nullish(hieroTransactionIdSchema, undefined), + hieroTransactionId: v.nullish(hieroTransactionIdStringSchema, undefined), topic: hieroIdSchema, }), v.custom((value: any) => { diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 92a994345..a22e8f27b 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -62,7 +62,9 @@ export class HieroClient { this.logger.info(`waiting for ${this.pendingPromises.length} pending promises`) await Promise.all(this.pendingPromises) const endTime = new Date() - this.logger.info(`all pending promises resolved, used time: ${endTime.getTime() - startTime.getTime()}ms`) + this.logger.info( + `all pending promises resolved, used time: ${endTime.getTime() - startTime.getTime()}ms`, + ) } public async sendMessage( @@ -85,28 +87,34 @@ export class HieroClient { }).freezeWithSigner(this.wallet) // sign and execute transaction needs some time, so let it run in background const pendingPromiseIndex = this.pendingPromises.push( - hieroTransaction.signWithSigner(this.wallet).then(async (signedHieroTransaction) => { - const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) - logger.info(`message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`) - if (logger.isInfoEnabled()) { - // only for logging - sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { - logger.info( - `message send status: ${receipt.status.toString()}`, - ) - }) - // only for logging - sendResponse.getRecordWithSigner(this.wallet).then((record) => { - logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - const localEndTime = new Date() - logger.info(`HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`) - }) - } - }).catch((e) => { - logger.error(e) - }).finally(() => { - this.pendingPromises.splice(pendingPromiseIndex, 1) - }) + hieroTransaction + .signWithSigner(this.wallet) + .then(async (signedHieroTransaction) => { + const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) + logger.info( + `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`, + ) + if (logger.isInfoEnabled()) { + // only for logging + sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { + logger.info(`message send status: ${receipt.status.toString()}`) + }) + // only for logging + sendResponse.getRecordWithSigner(this.wallet).then((record) => { + logger.info(`message sent, cost: ${record.transactionFee.toString()}`) + const localEndTime = new Date() + logger.info( + `HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`, + ) + }) + } + }) + .catch((e) => { + logger.error(e) + }) + .finally(() => { + this.pendingPromises.splice(pendingPromiseIndex, 1) + }), ) const endTime = new Date() logger.info(`HieroClient.sendMessage used time: ${endTime.getTime() - startTime.getTime()}ms`) @@ -148,7 +156,7 @@ export class HieroClient { autoRenewPeriod: undefined, autoRenewAccountId: undefined, }) - + transaction = await transaction.freezeWithSigner(this.wallet) transaction = await transaction.signWithSigner(this.wallet) const createResponse = await transaction.executeWithSigner(this.wallet) diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 164b78601..10e3cea39 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -1,5 +1,5 @@ import dotenv from 'dotenv' -import { parse, InferOutput, ValiError } from 'valibot' +import { InferOutput, parse, ValiError } from 'valibot' import { configSchema } from './schema' dotenv.config() @@ -8,15 +8,17 @@ type ConfigOutput = InferOutput let config: ConfigOutput try { - console.info('Config loading...') config = parse(configSchema, process.env) -} catch (error: Error | unknown) { +} catch (error) { if (error instanceof ValiError) { - console.error(`${error.issues[0].path[0].key}: ${error.message} received: ${error.issues[0].received}`) + // biome-ignore lint/suspicious/noConsole: need to parse config before initializing logger + console.error( + `${error.issues[0].path[0].key}: ${error.message} received: ${error.issues[0].received}`, + ) } else { + // biome-ignore lint/suspicious/noConsole: need to parse config before initializing logger console.error(error) } - // console.error('Config error:', JSON.stringify(error, null, 2)) process.exit(1) } diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index c64dda299..7ae40ea99 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -1,8 +1,25 @@ import { MemoryBlock } from 'gradido-blockchain-js' -import { ParameterError } from '../errors' +import { InvalidCallError, ParameterError } from '../errors' import { IdentifierKeyPair } from '../schemas/account.schema' -import { HieroId } from '../schemas/typeGuard.schema' +import { HieroId, IdentifierSeed, Uuidv4 } from '../schemas/typeGuard.schema' +/** + * @DCI-Logic + * Domain logic for identifying and classifying key pairs used in the Gradido blockchain. + * + * This logic determines the type of key pair (community, user, account, or seed) + * and provides deterministic methods for deriving consistent cache keys and hashes. + * It is pure, stateless, and guaranteed to operate on validated input + * (checked beforehand by Valibot using {@link identifierKeyPairSchema}). + * + * Responsibilities: + * - Identify key pair type via `isCommunityKeyPair()`, `isUserKeyPair()`, `isAccountKeyPair()`, or `isSeedKeyPair()` + * - Provide derived deterministic keys for caching or retrieval + * (e.g. `getCommunityUserKey()`, `getCommunityUserAccountKey()`) + * - or simple: `getKey()` if you don't need to know the details + * - Ensure that invalid method calls throw precise domain-specific errors + * (`InvalidCallError` for misuse, `ParameterError` for unexpected input) + */ export class KeyPairIdentifierLogic { public constructor(public identifier: IdentifierKeyPair) {} @@ -30,33 +47,27 @@ export class KeyPairIdentifierLogic { ) } - getSeed(): string { + getSeed(): IdentifierSeed { if (!this.identifier.seed) { - throw new Error( - 'get seed called on non seed key pair identifier, please check first with isSeedKeyPair()', - ) + throw new InvalidCallError('Invalid call: getSeed() on non-seed identifier') } - return this.identifier.seed.seed + return this.identifier.seed } getCommunityTopicId(): HieroId { return this.identifier.communityTopicId } - getUserUuid(): string { + getUserUuid(): Uuidv4 { if (!this.identifier.account) { - throw new Error( - 'get user uuid called on non user key pair identifier, please check first with isUserKeyPair() or isAccountKeyPair()', - ) + throw new InvalidCallError('Invalid call: getUserUuid() on non-user identifier') } return this.identifier.account.userUuid } getAccountNr(): number { - if (!this.identifier.account?.accountNr) { - throw new Error( - 'get account nr called on non account key pair identifier, please check first with isAccountKeyPair()', - ) + if (!this.identifier.account) { + throw new InvalidCallError('Invalid call: getAccountNr() on non-account identifier') } return this.identifier.account.accountNr } @@ -64,32 +75,36 @@ export class KeyPairIdentifierLogic { getSeedKey(): string { return this.getSeed() } - getCommunityKey(): HieroId { + getCommunityKey(): string { return this.getCommunityTopicId() } getCommunityUserKey(): string { - return this.createCommunityUserHash() + return this.deriveCommunityUserHash() } getCommunityUserAccountKey(): string { - return this.createCommunityUserHash() + this.getAccountNr().toString() + return this.deriveCommunityUserHash() + this.getAccountNr().toString() } getKey(): string { - if (this.isSeedKeyPair()) { - return this.getSeedKey() - } else if (this.isCommunityKeyPair()) { - return this.getCommunityKey() - } else if (this.isUserKeyPair()) { - return this.getCommunityUserKey() - } else if (this.isAccountKeyPair()) { - return this.getCommunityUserAccountKey() + switch (true) { + case this.isSeedKeyPair(): + return this.getSeedKey() + case this.isCommunityKeyPair(): + return this.getCommunityKey() + case this.isUserKeyPair(): + return this.getCommunityUserKey() + case this.isAccountKeyPair(): + return this.getCommunityUserAccountKey() + default: + throw new ParameterError('KeyPairIdentifier: unhandled input constellation') } - throw new ParameterError('KeyPairIdentifier: unhandled input type') } - private createCommunityUserHash(): string { - if (!this.identifier.account?.userUuid || !this.identifier.communityTopicId) { - throw new ParameterError('userUuid and/or communityTopicId is undefined') + private deriveCommunityUserHash(): string { + if (!this.identifier.account) { + throw new InvalidCallError( + 'Invalid call: getCommunityUserKey or getCommunityUserAccountKey() on non-user/non-account identifier', + ) } const resultString = this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') diff --git a/dlt-connector/src/errors.ts b/dlt-connector/src/errors.ts index 3bedb023a..907048f5a 100644 --- a/dlt-connector/src/errors.ts +++ b/dlt-connector/src/errors.ts @@ -55,3 +55,10 @@ export class ParameterError extends Error { this.name = 'ParameterError' } } + +export class InvalidCallError extends Error { + constructor(message: string) { + super(message) + this.name = 'InvalidCallError' + } +} diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 95f0068ce..2a681d300 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -7,6 +7,7 @@ import { BackendClient } from './client/backend/BackendClient' import { GradidoNodeClient } from './client/GradidoNode/GradidoNodeClient' import { HieroClient } from './client/hiero/HieroClient' import { CONFIG } from './config' +import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' import { SendToHieroContext } from './interactions/sendToHiero/SendToHiero.context' import { KeyPairCacheManager } from './KeyPairCacheManager' import { Community, communitySchema } from './schemas/transaction.schema' @@ -52,7 +53,7 @@ async function main() { function setupGracefulShutdown(logger: Logger) { const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'] - signals.forEach(sig => { + signals.forEach((sig) => { process.on(sig, async () => { logger.info(`[shutdown] Got ${sig}, cleaning up…`) await gracefulShutdown(logger) @@ -60,13 +61,13 @@ function setupGracefulShutdown(logger: Logger) { }) }) - if (process.platform === "win32") { - const rl = require("readline").createInterface({ + if (process.platform === 'win32') { + const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout, }) - rl.on("SIGINT", () => { - process.emit("SIGINT" as any) + rl.on('SIGINT', () => { + process.emit('SIGINT' as any) }) } } @@ -113,8 +114,8 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): } else { // if topic exist, check if we need to update it let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) - console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`) - /*if ( + // console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`) + if ( topicInfo.expirationTime.getTime() - new Date().getTime() < MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE ) { @@ -123,7 +124,7 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): logger.info( `updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`, ) - }*/ + } } if (!homeCommunity.hieroTopicId) { throw new Error('still no topic id, after creating topic and update community in backend.') @@ -140,4 +141,3 @@ main().catch((e) => { console.error(e) process.exit(1) }) - diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts deleted file mode 100644 index 7c7103d94..000000000 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { describe, it, expect, mock, beforeAll, afterAll } from 'bun:test' -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairCalculation } from './KeyPairCalculation.context' -import { parse } from 'valibot' -import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import { KeyPairCacheManager } from '../../KeyPairCacheManager' -import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { identifierKeyPairSchema } from '../../schemas/account.schema' -/* -// Mock JsonRpcClient -const mockRpcCall = mock((params) => { - console.log('mockRpcCall', params) - return { - isSuccess: () => false, - isError: () => true, - error: { - code: GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND - } - } -}) -const mockRpcCallResolved = mock() - -mock.module('../../utils/network', () => ({ - isPortOpenRetry: async () => true, -})) - -mock.module('jsonrpc-ts-client', () => { - return { - default: class MockJsonRpcClient { - constructor() {} - exec = mockRpcCall - }, - } -}) -*/ - -mock.module('../../KeyPairCacheManager', () => { - let homeCommunityTopicId: HieroId | undefined - return { - KeyPairCacheManager: { - getInstance: () => ({ - setHomeCommunityTopicId: (topicId: HieroId) => { - homeCommunityTopicId = topicId - }, - getHomeCommunityTopicId: () => homeCommunityTopicId, - getKeyPair: (key: string, create: () => KeyPairEd25519) => { - return create() - }, - }), - }, - } -}) - -mock.module('../../config', () => ({ - CONFIG: { - HOME_COMMUNITY_SEED: MemoryBlock.fromHex('0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7'), - }, -})) - -const topicId = '0.0.21732' -const userUuid = 'aa25cf6f-2879-4745-b2ea-6d3c37fb44b0' - -console.log('userUuid', userUuid) - -afterAll(() => { - mock.restore() -}) - -describe('KeyPairCalculation', () => { - beforeAll(() => { - KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) - }) - it('community key pair', async () => { - const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { communityTopicId: topicId })) - const keyPair = await KeyPairCalculation(identifier) - expect(keyPair.getPublicKey()?.convertToHex()).toBe('7bcb0d0ad26d3f7ba597716c38a570220cece49b959e57927ee0c39a5a9c3adf') - }) - it('user key pair', async () => { - const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { - communityTopicId: topicId, - account: { userUuid } - })) - expect(identifier.isAccountKeyPair()).toBe(false) - expect(identifier.isUserKeyPair()).toBe(true) - const keyPair = await KeyPairCalculation(identifier) - expect(keyPair.getPublicKey()?.convertToHex()).toBe('d61ae86c262fc0b5d763a8f41a03098fae73a7649a62aac844378a0eb0055921') - }) - - it('account key pair', async () => { - const identifier = new KeyPairIdentifierLogic(parse(identifierKeyPairSchema, { - communityTopicId: topicId, - account: { userUuid, accountNr: 1 } - })) - expect(identifier.isAccountKeyPair()).toBe(true) - expect(identifier.isUserKeyPair()).toBe(false) - const keyPair = await KeyPairCalculation(identifier) - expect(keyPair.getPublicKey()?.convertToHex()).toBe('6cffb0ee0b20dae828e46f2e003f78ac57b85e7268e587703932f06e1b2daee4') - }) -}) diff --git a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts b/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts deleted file mode 100644 index 883b214e8..000000000 --- a/dlt-connector/src/interactions/keyPairCalculation/KeyPairCalculation.context.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { KeyPairEd25519 } from 'gradido-blockchain-js' - -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairCacheManager } from '../../KeyPairCacheManager' -import { AccountKeyPairRole } from './AccountKeyPair.role' -import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' -import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' -import { LinkedTransactionKeyPairRole } from './LinkedTransactionKeyPair.role' -import { RemoteAccountKeyPairRole } from './RemoteAccountKeyPair.role' -import { UserKeyPairRole } from './UserKeyPair.role' - -/** - * @DCI-Context - * Context for calculating key pair for signing transactions - */ -export async function KeyPairCalculation(input: KeyPairIdentifierLogic): Promise { - const cache = KeyPairCacheManager.getInstance() - return await cache.getKeyPair(input.getKey(), async () => { - if (input.isSeedKeyPair()) { - return new LinkedTransactionKeyPairRole(input.getSeed()).generateKeyPair() - } - // If input does not belong to the home community, handle as remote key pair - if (cache.getHomeCommunityTopicId() !== input.getCommunityTopicId()) { - const role = input.isAccountKeyPair() - ? new RemoteAccountKeyPairRole(input.identifier) - : new ForeignCommunityKeyPairRole(input.getCommunityTopicId()) - return await role.retrieveKeyPair() - } - const communityKeyPair = await cache.getKeyPair(input.getCommunityKey(), async () => { - return new HomeCommunityKeyPairRole().generateKeyPair() - }) - if (!communityKeyPair) { - throw new Error("couldn't generate community key pair") - } - if (input.isCommunityKeyPair()) { - return communityKeyPair - } - const userKeyPair = await cache.getKeyPair(input.getCommunityUserKey(), async () => { - return new UserKeyPairRole(input.getUserUuid(), communityKeyPair).generateKeyPair() - }) - if (!userKeyPair) { - throw new Error("couldn't generate user key pair") - } - if (input.isUserKeyPair()) { - return userKeyPair - } - const accountNr = input.getAccountNr() - const accountKeyPair = new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() - if (input.isAccountKeyPair()) { - return accountKeyPair - } - throw new Error("couldn't generate account key pair, unexpected type") - }) -} diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/AbstractKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/AbstractKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/AbstractKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/AbstractRemoteKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/AccountKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/AccountKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/AccountKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/ForeignCommunityKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/HomeCommunityKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/HomeCommunityKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/HomeCommunityKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/LinkedTransactionKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/LinkedTransactionKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/LinkedTransactionKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/RemoteAccountKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts new file mode 100644 index 000000000..6d208eaff --- /dev/null +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts @@ -0,0 +1,84 @@ +import { afterAll, beforeAll, describe, expect, it, mock } from 'bun:test' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { parse } from 'valibot' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairCacheManager } from '../../KeyPairCacheManager' +import { identifierKeyPairSchema } from '../../schemas/account.schema' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { ResolveKeyPair } from './ResolveKeyPair.context' + +mock.module('../../KeyPairCacheManager', () => { + let homeCommunityTopicId: HieroId | undefined + return { + KeyPairCacheManager: { + getInstance: () => ({ + setHomeCommunityTopicId: (topicId: HieroId) => { + homeCommunityTopicId = topicId + }, + getHomeCommunityTopicId: () => homeCommunityTopicId, + getKeyPair: (key: string, create: () => KeyPairEd25519) => { + return create() + }, + }), + }, + } +}) + +mock.module('../../config', () => ({ + CONFIG: { + HOME_COMMUNITY_SEED: MemoryBlock.fromHex( + '0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7', + ), + }, +})) + +const topicId = '0.0.21732' +const userUuid = 'aa25cf6f-2879-4745-b2ea-6d3c37fb44b0' + +afterAll(() => { + mock.restore() +}) + +describe('KeyPairCalculation', () => { + beforeAll(() => { + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) + }) + it('community key pair', async () => { + const identifier = new KeyPairIdentifierLogic( + parse(identifierKeyPairSchema, { communityTopicId: topicId }), + ) + const keyPair = await ResolveKeyPair(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe( + '7bcb0d0ad26d3f7ba597716c38a570220cece49b959e57927ee0c39a5a9c3adf', + ) + }) + it('user key pair', async () => { + const identifier = new KeyPairIdentifierLogic( + parse(identifierKeyPairSchema, { + communityTopicId: topicId, + account: { userUuid }, + }), + ) + expect(identifier.isAccountKeyPair()).toBe(false) + expect(identifier.isUserKeyPair()).toBe(true) + const keyPair = await ResolveKeyPair(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe( + 'd61ae86c262fc0b5d763a8f41a03098fae73a7649a62aac844378a0eb0055921', + ) + }) + + it('account key pair', async () => { + const identifier = new KeyPairIdentifierLogic( + parse(identifierKeyPairSchema, { + communityTopicId: topicId, + account: { userUuid, accountNr: 1 }, + }), + ) + expect(identifier.isAccountKeyPair()).toBe(true) + expect(identifier.isUserKeyPair()).toBe(false) + const keyPair = await ResolveKeyPair(identifier) + expect(keyPair.getPublicKey()?.convertToHex()).toBe( + '6cffb0ee0b20dae828e46f2e003f78ac57b85e7268e587703932f06e1b2daee4', + ) + }) +}) diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts new file mode 100644 index 000000000..2fbdd906c --- /dev/null +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -0,0 +1,81 @@ +import { KeyPairEd25519 } from 'gradido-blockchain-js' + +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairCacheManager } from '../../KeyPairCacheManager' +import { AccountKeyPairRole } from './AccountKeyPair.role' +import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' +import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' +import { LinkedTransactionKeyPairRole } from './LinkedTransactionKeyPair.role' +import { RemoteAccountKeyPairRole } from './RemoteAccountKeyPair.role' +import { UserKeyPairRole } from './UserKeyPair.role' + +/** + * @DCI-Context + * Context for resolving the correct KeyPair for signing Gradido transactions. + * + * The context determines — based on the given {@link KeyPairIdentifierLogic} — + * which kind of KeyPair is required (community, user, account, remote, etc.). + * + * It first attempts to retrieve the KeyPair from the global {@link KeyPairCacheManager}. + * If no cached KeyPair exists, it dynamically generates or fetches it using the appropriate Role: + * - {@link LinkedTransactionKeyPairRole} for seed-based keys + * - {@link RemoteAccountKeyPairRole} or {@link ForeignCommunityKeyPairRole} for remote communities + * - {@link HomeCommunityKeyPairRole} for local community keys + * - {@link UserKeyPairRole} and {@link AccountKeyPairRole} for user and account levels + * + * Once generated, the KeyPair is stored in the cache for future reuse. + * + * @param input - Key pair identification logic containing all attributes + * (communityTopicId, userUuid, accountNr, seed, etc.) + * @returns The resolved {@link KeyPairEd25519} for the given input. + * + * @throws Error if the required KeyPair cannot be generated or resolved. + */ +export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { + const cache = KeyPairCacheManager.getInstance() + + return await cache.getKeyPair( + input.getKey(), + // function is called from cache manager, if key isn't currently cached + async () => { + // Seed (from linked transactions) + if (input.isSeedKeyPair()) { + return new LinkedTransactionKeyPairRole(input.getSeed()).generateKeyPair() + } + // Remote community branch + if (cache.getHomeCommunityTopicId() !== input.getCommunityTopicId()) { + const role = input.isAccountKeyPair() + ? new RemoteAccountKeyPairRole(input.identifier) + : new ForeignCommunityKeyPairRole(input.getCommunityTopicId()) + return await role.retrieveKeyPair() + } + // Community + const communityKeyPair = await cache.getKeyPair(input.getCommunityKey(), async () => { + return new HomeCommunityKeyPairRole().generateKeyPair() + }) + if (!communityKeyPair) { + throw new Error("couldn't generate community key pair") + } + if (input.isCommunityKeyPair()) { + return communityKeyPair + } + // User + const userKeyPair = await cache.getKeyPair(input.getCommunityUserKey(), async () => { + return new UserKeyPairRole(input.getUserUuid(), communityKeyPair).generateKeyPair() + }) + if (!userKeyPair) { + throw new Error("couldn't generate user key pair") + } + if (input.isUserKeyPair()) { + return userKeyPair + } + // Account + const accountNr = input.getAccountNr() + const accountKeyPair = new AccountKeyPairRole(accountNr, userKeyPair).generateKeyPair() + if (input.isAccountKeyPair()) { + return accountKeyPair + } + throw new Error("couldn't generate account key pair, unexpected type") + }, + ) +} diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/UserKeyPair.role.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/UserKeyPair.role.ts rename to dlt-connector/src/interactions/resolveKeyPair/UserKeyPair.role.ts diff --git a/dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts b/dlt-connector/src/interactions/resolveKeyPair/UserKeyPairRole.test.ts similarity index 100% rename from dlt-connector/src/interactions/keyPairCalculation/UserKeyPairRole.test.ts rename to dlt-connector/src/interactions/resolveKeyPair/UserKeyPairRole.test.ts diff --git a/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts index 34299683a..6207e28ec 100644 --- a/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CommunityRootTransaction.role.ts @@ -8,7 +8,7 @@ import { GMW_ACCOUNT_DERIVATION_INDEX, hardenDerivationIndex, } from '../../utils/derivationHelper' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class CommunityRootTransactionRole extends AbstractTransactionRole { @@ -26,7 +26,7 @@ export class CommunityRootTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const communityKeyPair = await KeyPairCalculation( + const communityKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic({ communityTopicId: this.community.hieroTopicId }), ) const gmwKeyPair = communityKeyPair.deriveChild( diff --git a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts index fd70682ea..d11b031e2 100644 --- a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts @@ -13,7 +13,7 @@ import { Transaction, } from '../../schemas/transaction.schema' import { HieroId } from '../../schemas/typeGuard.schema' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class CreationTransactionRole extends AbstractTransactionRole { @@ -21,12 +21,7 @@ export class CreationTransactionRole extends AbstractTransactionRole { private readonly creationTransaction: CreationTransaction constructor(transaction: Transaction) { super() - try { - this.creationTransaction = parse(creationTransactionSchema, transaction) - } catch (error) { - console.error('creation: invalid transaction', JSON.stringify(error, null, 2)) - throw new Error('creation: invalid transaction') - } + this.creationTransaction = parse(creationTransactionSchema, transaction) this.homeCommunityTopicId = KeyPairCacheManager.getInstance().getHomeCommunityTopicId() if ( this.homeCommunityTopicId !== this.creationTransaction.user.communityTopicId || @@ -47,14 +42,14 @@ export class CreationTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() // Recipient: user (account owner) - const recipientKeyPair = await KeyPairCalculation( + const recipientKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.creationTransaction.user), ) // Signer: linkedUser (admin/moderator) - const signerKeyPair = await KeyPairCalculation( + const signerKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.creationTransaction.linkedUser), ) - const homeCommunityKeyPair = await KeyPairCalculation( + const homeCommunityKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic({ communityTopicId: this.homeCommunityTopicId, }), diff --git a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts index 36569d708..ac0b924f6 100644 --- a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts @@ -7,14 +7,13 @@ import { } from 'gradido-blockchain-js' import { parse } from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { IdentifierSeed, identifierSeedSchema } from '../../schemas/account.schema' import { DeferredTransferTransaction, deferredTransferTransactionSchema, Transaction, } from '../../schemas/transaction.schema' -import { HieroId } from '../../schemas/typeGuard.schema' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { HieroId, IdentifierSeed, identifierSeedSchema } from '../../schemas/typeGuard.schema' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class DeferredTransferTransactionRole extends AbstractTransactionRole { @@ -36,10 +35,10 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation( + const senderKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.deferredTransferTransaction.user), ) - const recipientKeyPair = await KeyPairCalculation( + const recipientKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic({ communityTopicId: this.deferredTransferTransaction.linkedUser.communityTopicId, seed: this.seed, diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index a91990360..76d621762 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -9,7 +9,7 @@ import { UserAccount, } from '../../schemas/transaction.schema' import { HieroId } from '../../schemas/typeGuard.schema' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRole { @@ -34,7 +34,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() - const senderKeyPair = await KeyPairCalculation( + const senderKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.redeemDeferredTransferTransaction.user), ) const senderPublicKey = senderKeyPair.getPublicKey() @@ -56,7 +56,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", ) } - const recipientKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(this.linkedUser)) + const recipientKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic(this.linkedUser)) builder .setCreatedAt(this.redeemDeferredTransferTransaction.createdAt) diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index 032ec5eec..968a3c992 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -1,11 +1,9 @@ -import { describe, it, expect } from 'bun:test' -import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' -import { parse } from 'valibot' -import { - transactionSchema, -} from '../../schemas/transaction.schema' -import { hieroIdSchema } from '../../schemas/typeGuard.schema' +import { describe, expect, it } from 'bun:test' import { InteractionToJson, InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' +import { parse } from 'valibot' +import { transactionSchema } from '../../schemas/transaction.schema' +import { hieroIdSchema } from '../../schemas/typeGuard.schema' +import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' const userUuid = '408780b2-59b3-402a-94be-56a4f4f4e8ec' const transaction = { @@ -21,15 +19,21 @@ const transaction = { createdAt: '2022-01-01T00:00:00.000Z', } -describe('RegisterAddressTransaction.role', () => { +describe('RegisterAddressTransaction.role', () => { it('get correct prepared builder', async () => { - const registerAddressTransactionRole = new RegisterAddressTransactionRole(parse(transactionSchema, transaction)) - expect(registerAddressTransactionRole.getSenderCommunityTopicId()).toBe(parse(hieroIdSchema, '0.0.21732')) - expect(() => registerAddressTransactionRole.getRecipientCommunityTopicId()).toThrow() - const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() - const gradidoTransaction = builder.build() - expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() - const json = JSON.parse(new InteractionToJson(gradidoTransaction).run()) - expect(json.bodyBytes.json.registerAddress.nameHash).toBe('bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08') + const registerAddressTransactionRole = new RegisterAddressTransactionRole( + parse(transactionSchema, transaction), + ) + expect(registerAddressTransactionRole.getSenderCommunityTopicId()).toBe( + parse(hieroIdSchema, '0.0.21732'), + ) + expect(() => registerAddressTransactionRole.getRecipientCommunityTopicId()).toThrow() + const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() + const gradidoTransaction = builder.build() + expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() + const json = JSON.parse(new InteractionToJson(gradidoTransaction).run()) + expect(json.bodyBytes.json.registerAddress.nameHash).toBe( + 'bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08', + ) }) -}) \ No newline at end of file +}) diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index 32f78bac1..8f0f50e6b 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -12,7 +12,7 @@ import { Transaction, } from '../../schemas/transaction.schema' import { HieroId } from '../../schemas/typeGuard.schema' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class RegisterAddressTransactionRole extends AbstractTransactionRole { @@ -35,15 +35,13 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const communityTopicId = this.registerAddressTransaction.user.communityTopicId - const communityKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic({ communityTopicId })) + const communityKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic({ communityTopicId })) const keyPairIdentifier = this.registerAddressTransaction.user // when accountNr is 0 it is the user account keyPairIdentifier.account.accountNr = 0 - const userKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(keyPairIdentifier)) + const userKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic(keyPairIdentifier)) keyPairIdentifier.account.accountNr = 1 - const accountKeyPair = await KeyPairCalculation( - new KeyPairIdentifierLogic(keyPairIdentifier), - ) + const accountKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic(keyPairIdentifier)) builder .setCreatedAt(this.registerAddressTransaction.createdAt) diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 5061233be..e3ab0b7ed 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -1,24 +1,25 @@ import { GradidoTransaction, + HieroTransactionId, + InteractionSerialize, InteractionValidate, - MemoryBlock, ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { parse, safeParse } from 'valibot' +import * as v from 'valibot' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { InputTransactionType } from '../../enum/InputTransactionType' import { - Community, + CommunityInput, communitySchema, - Transaction, + TransactionInput, transactionSchema, } from '../../schemas/transaction.schema' import { HieroId, - HieroTransactionId, - hieroTransactionIdSchema, + HieroTransactionIdString, + hieroTransactionIdStringSchema, } from '../../schemas/typeGuard.schema' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' @@ -36,70 +37,99 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendT * send every transaction only once to hiero! */ export async function SendToHieroContext( - input: Transaction | Community, -): Promise { - // let gradido blockchain validator run, it will throw an exception when something is wrong - const validate = (transaction: GradidoTransaction): void => { - const validator = new InteractionValidate(transaction) - validator.run(ValidateType_SINGLE) - } - - // send transaction as hiero topic message - const sendViaHiero = async ( - gradidoTransaction: GradidoTransaction, - topic: HieroId, - ): Promise => { - const client = HieroClient.getInstance() - const transactionId = await client.sendMessage(topic, gradidoTransaction) - if (!transactionId) { - throw new Error('missing transaction id from hiero') - } - logger.info('transmitted Gradido Transaction to Hiero', { transactionId: transactionId.toString() }) - return transactionId.toString() - } - - // choose correct role based on transaction type and input type - const chooseCorrectRole = (input: Transaction | Community): AbstractTransactionRole => { - const communityParsingResult = safeParse(communitySchema, input) - if (communityParsingResult.success) { - return new CommunityRootTransactionRole(communityParsingResult.output) - } - - const transaction = input as Transaction - switch (transaction.type) { - case InputTransactionType.GRADIDO_CREATION: - return new CreationTransactionRole(transaction) - case InputTransactionType.GRADIDO_TRANSFER: - return new TransferTransactionRole(transaction) - case InputTransactionType.REGISTER_ADDRESS: - return new RegisterAddressTransactionRole(transaction) - case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: - return new DeferredTransferTransactionRole(transaction) - case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: - return new RedeemDeferredTransferTransactionRole(transaction) - default: - throw new Error('not supported transaction type: ' + transaction.type) - } - } - + input: TransactionInput | CommunityInput, +): Promise { const role = chooseCorrectRole(input) const builder = await role.getGradidoTransactionBuilder() if (builder.isCrossCommunityTransaction()) { + // build cross group transaction const outboundTransaction = builder.buildOutbound() validate(outboundTransaction) - const outboundHieroTransactionId = await sendViaHiero( + + // send outbound transaction to hiero at first, because we need the transaction id for inbound transaction + const outboundHieroTransactionIdString = await sendViaHiero( outboundTransaction, role.getSenderCommunityTopicId(), ) - builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundHieroTransactionId))) + + // serialize Hiero transaction ID and attach it to the builder for the inbound transaction + const transactionIdSerializer = new InteractionSerialize( + new HieroTransactionId(outboundHieroTransactionIdString), + ) + builder.setParentMessageId(transactionIdSerializer.run()) + + // build and validate inbound transaction const inboundTransaction = builder.buildInbound() validate(inboundTransaction) + + // send inbound transaction to hiero await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId()) - return parse(hieroTransactionIdSchema, outboundHieroTransactionId) + return outboundHieroTransactionIdString } else { + // build and validate local transaction const transaction = builder.build() validate(transaction) - const hieroTransactionId = await sendViaHiero(transaction, role.getSenderCommunityTopicId()) - return parse(hieroTransactionIdSchema, hieroTransactionId) + + // send transaction to hiero + const hieroTransactionIdString = await sendViaHiero( + transaction, + role.getSenderCommunityTopicId(), + ) + return hieroTransactionIdString + } +} + +// let gradido blockchain validator run, it will throw an exception when something is wrong +function validate(transaction: GradidoTransaction): void { + const validator = new InteractionValidate(transaction) + validator.run(ValidateType_SINGLE) +} + +// send transaction as hiero topic message +async function sendViaHiero( + gradidoTransaction: GradidoTransaction, + topic: HieroId, +): Promise { + const client = HieroClient.getInstance() + const transactionId = await client.sendMessage(topic, gradidoTransaction) + if (!transactionId) { + throw new Error('missing transaction id from hiero') + } + logger.info('transmitted Gradido Transaction to Hiero', { + transactionId: transactionId.toString(), + }) + return v.parse(hieroTransactionIdStringSchema, transactionId.toString()) +} + +// choose correct role based on transaction type and input type +function chooseCorrectRole(input: TransactionInput | CommunityInput): AbstractTransactionRole { + const communityParsingResult = v.safeParse(communitySchema, input) + if (communityParsingResult.success) { + return new CommunityRootTransactionRole(communityParsingResult.output) + } + + const transactionParsingResult = v.safeParse(transactionSchema, input) + if (!transactionParsingResult.success) { + logger.error("error validating transaction, doesn't match any schema", { + transactionSchema: v.flatten(transactionParsingResult.issues), + communitySchema: v.flatten(communityParsingResult.issues), + }) + throw new Error('invalid input') + } + + const transaction = transactionParsingResult.output + switch (transaction.type) { + case InputTransactionType.GRADIDO_CREATION: + return new CreationTransactionRole(transaction) + case InputTransactionType.GRADIDO_TRANSFER: + return new TransferTransactionRole(transaction) + case InputTransactionType.REGISTER_ADDRESS: + return new RegisterAddressTransactionRole(transaction) + case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: + return new DeferredTransferTransactionRole(transaction) + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + return new RedeemDeferredTransferTransactionRole(transaction) + default: + throw new Error('not supported transaction type: ' + transaction.type) } } diff --git a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts index 473bfbc1e..03d1480b9 100644 --- a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts @@ -12,7 +12,7 @@ import { transferTransactionSchema, } from '../../schemas/transaction.schema' import { HieroId } from '../../schemas/typeGuard.schema' -import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../resolveKeyPair/ResolveKeyPair.context' import { AbstractTransactionRole } from './AbstractTransaction.role' export class TransferTransactionRole extends AbstractTransactionRole { @@ -33,11 +33,11 @@ export class TransferTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() // sender + signer - const senderKeyPair = await KeyPairCalculation( + const senderKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.transferTransaction.user), ) // recipient - const recipientKeyPair = await KeyPairCalculation( + const recipientKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic(this.transferTransaction.linkedUser), ) diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts index d1dbb4802..e328a2f90 100644 --- a/dlt-connector/src/schemas/account.schema.ts +++ b/dlt-connector/src/schemas/account.schema.ts @@ -1,12 +1,5 @@ import * as v from 'valibot' -import { hieroIdSchema, uuidv4Schema } from './typeGuard.schema' - -// use code from transaction links -export const identifierSeedSchema = v.object({ - seed: v.pipe(v.string('expect string type'), v.length(24, 'expect seed length 24')), -}) - -export type IdentifierSeed = v.InferOutput +import { hieroIdSchema, identifierSeedSchema, uuidv4Schema } from './typeGuard.schema' // identifier for gradido community accounts, inside a community export const identifierCommunityAccountSchema = v.object({ diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index 7d204dba5..de87cacfd 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -1,23 +1,28 @@ import { beforeAll, describe, expect, it } from 'bun:test' -import { TypeBoxFromValibot } from '@sinclair/typemap' import { TypeCompiler } from '@sinclair/typebox/compiler' +import { TypeBoxFromValibot } from '@sinclair/typemap' import { randomBytes } from 'crypto' +import { AddressType_COMMUNITY_HUMAN } from 'gradido-blockchain-js' import { v4 as uuidv4 } from 'uuid' import { parse } from 'valibot' +import { AccountType } from '../enum/AccountType' import { InputTransactionType } from '../enum/InputTransactionType' import { gradidoAmountSchema, HieroId, hieroIdSchema, + identifierSeedSchema, Memo, memoSchema, timeoutDurationSchema, Uuidv4, uuidv4Schema, } from '../schemas/typeGuard.schema' -import { registerAddressTransactionSchema, TransactionInput, transactionSchema } from './transaction.schema' -import { AccountType } from '../enum/AccountType' -import { AddressType_COMMUNITY_HUMAN } from 'gradido-blockchain-js' +import { + registerAddressTransactionSchema, + TransactionInput, + transactionSchema, +} from './transaction.schema' const transactionLinkCode = (date: Date): string => { const time = date.getTime().toString(16) @@ -91,7 +96,7 @@ describe('transaction schemas', () => { expect(check.Check(registerAddress)).toBe(true) }) }) - + it('valid, gradido transfer', () => { const gradidoTransfer: TransactionInput = { user: { @@ -162,6 +167,8 @@ describe('transaction schemas', () => { }) }) it('valid, gradido transaction link / deferred transfer', () => { + const seed = transactionLinkCode(new Date()) + const seedParsed = parse(identifierSeedSchema, seed) const gradidoTransactionLink: TransactionInput = { user: { communityTopicId: topicString, @@ -171,9 +178,7 @@ describe('transaction schemas', () => { }, linkedUser: { communityTopicId: topicString, - seed: { - seed: transactionLinkCode(new Date()), - }, + seed, }, amount: '100', memo: memoString, @@ -191,9 +196,7 @@ describe('transaction schemas', () => { }, linkedUser: { communityTopicId: topic, - seed: { - seed: gradidoTransactionLink.linkedUser!.seed!.seed, - }, + seed: seedParsed, }, amount: parse(gradidoAmountSchema, gradidoTransactionLink.amount!), memo, diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index 7c1855ec8..dea8c48dc 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -1,19 +1,16 @@ import * as v from 'valibot' +import { AccountType } from '../enum/AccountType' import { InputTransactionType } from '../enum/InputTransactionType' -import { - identifierAccountSchema, - identifierCommunityAccountSchema, - identifierSeedSchema, -} from './account.schema' +import { identifierAccountSchema, identifierCommunityAccountSchema } from './account.schema' import { addressTypeSchema, dateSchema } from './typeConverter.schema' import { gradidoAmountSchema, hieroIdSchema, + identifierSeedSchema, memoSchema, timeoutDurationSchema, uuidv4Schema, } from './typeGuard.schema' -import { AccountType } from '../enum/AccountType' /** * Schema for community, for creating new CommunityRoot Transaction on gradido blockchain diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index dd8944247..2caa499b5 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -1,7 +1,7 @@ -import { Static, TypeBoxFromValibot } from '@sinclair/typemap' -import { TypeCompiler } from '@sinclair/typebox/compiler' // only for IDE, bun don't need this to work import { describe, expect, it } from 'bun:test' +import { TypeCompiler } from '@sinclair/typebox/compiler' +import { Static, TypeBoxFromValibot } from '@sinclair/typemap' import { AddressType_COMMUNITY_AUF } from 'gradido-blockchain-js' import * as v from 'valibot' import { AccountType } from '../enum/AccountType' @@ -26,25 +26,25 @@ describe('basic.schema', () => { expect(() => v.parse(dateSchema, 'invalid date')).toThrow(new Error('invalid date')) }) it('with type box', () => { - // Derive TypeBox Schema from the Valibot Schema - const DateSchema = TypeBoxFromValibot(dateSchema) + // Derive TypeBox Schema from the Valibot Schema + const DateSchema = TypeBoxFromValibot(dateSchema) - // Build the compiler - const check = TypeCompiler.Compile(DateSchema) - - // Valid value (String) - expect(check.Check('2021-01-01T10:10:00.000Z')).toBe(true) - - // typebox cannot use valibot custom validation and transformations, it will check only the input types - expect(check.Check('invalid date')).toBe(true) - - // Type inference (TypeScript) - type DateType = Static - const validDate: DateType = '2021-01-01T10:10:00.000Z' - const validDate2: DateType = new Date('2021-01-01') + // Build the compiler + const check = TypeCompiler.Compile(DateSchema) - // @ts-expect-error - const invalidDate: DateType = 123 // should fail in TS + // Valid value (String) + expect(check.Check('2021-01-01T10:10:00.000Z')).toBe(true) + + // typebox cannot use valibot custom validation and transformations, it will check only the input types + expect(check.Check('invalid date')).toBe(true) + + // Type inference (TypeScript) + type DateType = Static + const _validDate: DateType = '2021-01-01T10:10:00.000Z' + const _validDate2: DateType = new Date('2021-01-01') + + // @ts-expect-error + const _invalidDate: DateType = 123 // should fail in TS }) }) @@ -74,16 +74,24 @@ describe('basic.schema', () => { const check = TypeCompiler.Compile(AddressTypeSchema) expect(check.Check(AccountType.COMMUNITY_AUF)).toBe(true) // type box will throw an error, because it cannot handle valibots custom validation - expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) - expect(() => check.Check('invalid')).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow( + new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`), + ) + expect(() => check.Check('invalid')).toThrow( + new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`), + ) }) it('accountType with type box', () => { const AccountTypeSchema = TypeBoxFromValibot(accountTypeSchema) const check = TypeCompiler.Compile(AccountTypeSchema) expect(check.Check(AccountType.COMMUNITY_AUF)).toBe(true) // type box will throw an error, because it cannot handle valibots custom validation - expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) - expect(() => check.Check('invalid')).toThrow(new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`)) + expect(() => check.Check(AddressType_COMMUNITY_AUF)).toThrow( + new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`), + ) + expect(() => check.Check('invalid')).toThrow( + new TypeError(`undefined is not an object (evaluating 'schema["~run"]')`), + ) }) }) diff --git a/dlt-connector/src/schemas/typeGuard.schema.ts b/dlt-connector/src/schemas/typeGuard.schema.ts index d580abe3a..3a93ac62f 100644 --- a/dlt-connector/src/schemas/typeGuard.schema.ts +++ b/dlt-connector/src/schemas/typeGuard.schema.ts @@ -39,6 +39,24 @@ export const uuidv4Schema = v.pipe( export type Uuidv4Input = v.InferInput +/** + * type guard for seed string + * create with `v.parse(seedSchema, '0c4676adfd96519a0551596c')` + * seed is a string of length 24 + */ +declare const validIdentifierSeed: unique symbol +export type IdentifierSeed = string & { [validIdentifierSeed]: true } + +// use code from transaction links +export const identifierSeedSchema = v.pipe( + v.string('expect string type'), + v.hexadecimal('expect hexadecimal string'), + v.length(24, 'expect seed length 24'), + v.transform((input: string) => input as IdentifierSeed), +) + +export type IdentifierSeedInput = v.InferInput + /** * type guard for memory block size 32 * create with `v.parse(memoryBlock32Schema, MemoryBlock.fromHex('39568d7e148a0afee7f27a67dbf7d4e87d1fdec958e2680df98a469690ffc1a2'))` @@ -124,16 +142,20 @@ export type HieroIdInput = v.InferInput * basically it is a Hiero id with a timestamp seconds-nanoseconds since 1970-01-01T00:00:00Z * seconds is int64, nanoseconds int32 */ -declare const validHieroTransactionId: unique symbol -export type HieroTransactionId = string & { [validHieroTransactionId]: true } +declare const validHieroTransactionIdString: unique symbol +export type HieroTransactionIdString = string & { [validHieroTransactionIdString]: true } -export const hieroTransactionIdSchema = v.pipe( - v.string('expect hiero transaction id type, for example 0.0.141760-1755138896-607329203 or 0.0.141760@1755138896.607329203'), +export const hieroTransactionIdStringSchema = v.pipe( + v.string( + 'expect hiero transaction id type, for example 0.0.141760-1755138896-607329203 or 0.0.141760@1755138896.607329203', + ), v.regex(/^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+-[0-9]+|@[0-9]+\.[0-9]+)$/), - v.transform((input: string) => input as HieroTransactionId), + v.transform( + (input: string) => input as HieroTransactionIdString, + ), ) -export type HieroTransactionIdInput = v.InferInput +export type HieroTransactionIdInput = v.InferInput /** * type guard for memo @@ -176,14 +198,12 @@ export const timeoutDurationSchema = v.pipe( ), v.instance(DurationSeconds, 'expect DurationSeconds type'), ]), - v.transform( - (input: number | DurationSeconds) => { - if (input instanceof DurationSeconds) { - return input as TimeoutDuration - } - return new DurationSeconds(input) as TimeoutDuration - }, - ), + v.transform((input: number | DurationSeconds) => { + if (input instanceof DurationSeconds) { + return input as TimeoutDuration + } + return new DurationSeconds(input) as TimeoutDuration + }), ) /** @@ -210,16 +230,11 @@ declare const validGradidoAmount: unique symbol export type GradidoAmount = GradidoUnit & { [validGradidoAmount]: true } export const gradidoAmountSchema = v.pipe( - v.union([ - amountSchema, - v.instance(GradidoUnit, 'expect GradidoUnit type'), - ]), - v.transform( - (input: Amount | GradidoUnit) => { - if (input instanceof GradidoUnit) { - return input as GradidoAmount - } - return GradidoUnit.fromString(input) as GradidoAmount - }, - ), + v.union([amountSchema, v.instance(GradidoUnit, 'expect GradidoUnit type')]), + v.transform((input: Amount | GradidoUnit) => { + if (input instanceof GradidoUnit) { + return input as GradidoAmount + } + return GradidoUnit.fromString(input) as GradidoAmount + }), ) diff --git a/dlt-connector/src/server/index.test.ts b/dlt-connector/src/server/index.test.ts index f3a9aed7d..3fa0ce07b 100644 --- a/dlt-connector/src/server/index.test.ts +++ b/dlt-connector/src/server/index.test.ts @@ -1,10 +1,10 @@ -import { appRoutes } from '.' -import { describe, it, expect, beforeAll, mock } from 'bun:test' -import { KeyPairCacheManager } from '../KeyPairCacheManager' -import { hieroIdSchema } from '../schemas/typeGuard.schema' -import { parse } from 'valibot' -import { HieroId } from '../schemas/typeGuard.schema' +import { beforeAll, describe, expect, it, mock } from 'bun:test' +import { AccountId, Timestamp, TransactionId } from '@hashgraph/sdk' import { GradidoTransaction, KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { parse } from 'valibot' +import { KeyPairCacheManager } from '../KeyPairCacheManager' +import { HieroId, hieroIdSchema } from '../schemas/typeGuard.schema' +import { appRoutes } from '.' const userUuid = '408780b2-59b3-402a-94be-56a4f4f4e8ec' @@ -29,7 +29,7 @@ mock.module('../client/hiero/HieroClient', () => ({ HieroClient: { getInstance: () => ({ sendMessage: (topicId: HieroId, transaction: GradidoTransaction) => { - return { receipt: { status: '0.0.21732' }, response: { transactionId: '0.0.6566984@1758029639.561157605' } } + return new TransactionId(new AccountId(0, 0, 6566984), new Timestamp(1758029639, 561157605)) }, }), }, @@ -37,7 +37,9 @@ mock.module('../client/hiero/HieroClient', () => ({ mock.module('../config', () => ({ CONFIG: { - HOME_COMMUNITY_SEED: MemoryBlock.fromHex('0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7'), + HOME_COMMUNITY_SEED: MemoryBlock.fromHex( + '0102030401060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe7', + ), }, })) @@ -59,17 +61,22 @@ describe('Server', () => { accountType: 'COMMUNITY_HUMAN', createdAt: '2022-01-01T00:00:00.000Z', } - const response = await appRoutes.handle(new Request('http://localhost/sendTransaction', { - method: 'POST', - body: JSON.stringify(transaction), - headers: { - 'Content-Type': 'application/json', - }, - })) + const response = await appRoutes.handle( + new Request('http://localhost/sendTransaction', { + method: 'POST', + body: JSON.stringify(transaction), + headers: { + 'Content-Type': 'application/json', + }, + }), + ) if (response.status !== 200) { + // biome-ignore lint/suspicious/noConsole: helper for debugging if test fails console.log(await response.text()) } expect(response.status).toBe(200) - expect(await response.text()).toBe('0.0.6566984@1758029639.561157605') + expect(await response.json()).toMatchObject({ + transactionId: '0.0.6566984@1758029639.561157605', + }) }) }) diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index b8aa44fd3..7168a76dc 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,92 +1,147 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' -import { Type } from '@sinclair/typebox' import { Elysia, status, t } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { parse } from 'valibot' +import * as v from 'valibot' import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' import { LOG4JS_BASE_CATEGORY } from '../config/const' import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' -import { KeyPairCalculation } from '../interactions/keyPairCalculation/KeyPairCalculation.context' +import { ResolveKeyPair } from '../interactions/resolveKeyPair/ResolveKeyPair.context' import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' -import { IdentifierAccount, identifierAccountSchema } from '../schemas/account.schema' +import { IdentifierAccountInput, identifierAccountSchema } from '../schemas/account.schema' import { transactionSchema } from '../schemas/transaction.schema' -import { hieroIdSchema, hieroTransactionIdSchema } from '../schemas/typeGuard.schema' +import { hieroTransactionIdStringSchema } from '../schemas/typeGuard.schema' import { - accountIdentifierSeedSchema, - accountIdentifierUserSchema, - existSchema, + accountIdentifierSeedTypeBoxSchema, + accountIdentifierUserTypeBoxSchema, + existTypeBoxSchema, } from './input.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) +/** + * To define a route in Elysia: + * + * 1. Choose the HTTP method: get, post, patch, put, or delete. + * + * 2. Define the route path: + * - **Params**: values inside the path. + * Example: path: `/isCommunityExist/:communityTopicId` + * → called with: GET `/isCommunityExist/0.0.21732` + * + * - **Query**: values in the query string. + * Example: path: `/isCommunityExist` + * → called with: GET `/isCommunityExist?communityTopicId=0.0.21732` + * + * 3. Write the route handler: + * Return a JSON object — often by calling your business logic. + * + * 4. Define validation schemas using TypeBoxFromValibot: + * - `params` (for path parameters) + * - `query` (for query strings) + * - `body` (for POST/PUT/PATCH requests) + * - `response` (for output) + * + * Example: + * .get( + * '/isCommunityExist/:communityTopicId', + * async ({ params: { communityTopicId } }) => ({ + * exists: await isCommunityExist({ communityTopicId }) + * }), + * { + * params: t.Object({ communityTopicId: TypeBoxFromValibot(hieroIdSchema) }), + * response: t.Object({ exists: t.Boolean() }), + * }, + * ) + * + * 🔗 More info: https://elysiajs.com/at-glance.html + */ export const appRoutes = new Elysia() + // check if account exists by user, call example: + // GET /isAccountExist/by-user/0.0.21732/408780b2-59b3-402a-94be-56a4f4f4e8ec/0 .get( '/isAccountExist/by-user/:communityTopicId/:userUuid/:accountNr', - async ({ params: { communityTopicId, userUuid, accountNr } }) => { - const accountIdentifier = parse(identifierAccountSchema, { + async ({ params: { communityTopicId, userUuid, accountNr } }) => ({ + exists: await isAccountExist({ communityTopicId, account: { userUuid, accountNr }, - }) - return { exists: await isAccountExist(accountIdentifier) } + }), + }), + { + params: accountIdentifierUserTypeBoxSchema, + response: existTypeBoxSchema, }, - // validation schemas - { params: accountIdentifierUserSchema, response: existSchema }, ) + // check if account exists by seed, call example: + // GET /isAccountExist/by-seed/0.0.21732/0c4676adfd96519a0551596c .get( '/isAccountExist/by-seed/:communityTopicId/:seed', - async ({ params: { communityTopicId, seed } }) => { - const accountIdentifier = parse(identifierAccountSchema, { + async ({ params: { communityTopicId, seed } }) => ({ + exists: await isAccountExist({ communityTopicId, - seed: { seed }, - }) - return { exists: await isAccountExist(accountIdentifier) } + seed, + }), + }), + { + params: accountIdentifierSeedTypeBoxSchema, + response: existTypeBoxSchema, }, - // validation schemas - { params: accountIdentifierSeedSchema, response: existSchema }, ) + // send transaction to hiero, call example for send transaction: + // POST /sendTransaction + // body: { + // user: { + // communityTopicId: '0.0.21732', + // account: { + // userUuid: '408780b2-59b3-402a-94be-56a4f4f4e8ec', + // accountNr: 0, + // }, + // }, + // linkedUser: { + // communityTopicId: '0.0.21732', + // account: { + // userUuid: '10689787-00fe-4295-a996-05c0952558d9', + // accountNr: 0, + // }, + // }, + // amount: 10, + // memo: 'test', + // type: 'TRANSFER', + // createdAt: '2022-01-01T00:00:00.000Z', + // } .post( '/sendTransaction', - async ({ body }) => { - try { - const hieroTransactionId = await SendToHieroContext(parse(transactionSchema, body)) - console.log('server will return:', hieroTransactionId) - return { transactionId: hieroTransactionId } - } catch (e) { - if (e instanceof TypeError) { - console.log(`message: ${e.message}, stack: ${e.stack}`) - } - console.log(e) - throw status(500, e) - } - }, - // validation schemas + async ({ body }) => ({ + transactionId: await SendToHieroContext(body), + }), { body: TypeBoxFromValibot(transactionSchema), - response: t.Object({ transactionId: TypeBoxFromValibot(hieroTransactionIdSchema) }), + response: t.Object({ transactionId: TypeBoxFromValibot(hieroTransactionIdStringSchema) }), }, ) -async function isAccountExist(identifierAccount: IdentifierAccount): Promise { +// function stay here for now because it is small and simple, but maybe later if more functions are added, move it to a separate file +async function isAccountExist(identifierAccount: IdentifierAccountInput): Promise { + // check and prepare input const startTime = Date.now() - const accountKeyPair = await KeyPairCalculation(new KeyPairIdentifierLogic(identifierAccount)) + const identifierAccountParsed = v.parse(identifierAccountSchema, identifierAccount) + const accountKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic(identifierAccountParsed)) const publicKey = accountKeyPair.getPublicKey() if (!publicKey) { - throw status(404, "couldn't calculate account key pair") + throw status(404, { message: "couldn't calculate account key pair" }) } // ask gradido node server for account type, if type !== NONE account exist const addressType = await GradidoNodeClient.getInstance().getAddressType( publicKey.convertToHex(), - identifierAccount.communityTopicId, + identifierAccountParsed.communityTopicId, ) + const exists = addressType !== AddressType_NONE const endTime = Date.now() - logger.info( - `isAccountExist: ${addressType !== AddressType_NONE}, time used: ${endTime - startTime}ms`, - ) + logger.info(`isAccountExist: ${exists}, time used: ${endTime - startTime}ms`) if (logger.isDebugEnabled()) { - logger.debug('params', identifierAccount) + logger.debug('params', identifierAccountParsed) } - return addressType !== AddressType_NONE + return exists } -export type DltRoutes = typeof appRoutes \ No newline at end of file +export type DltRoutes = typeof appRoutes diff --git a/dlt-connector/src/server/input.schema.ts b/dlt-connector/src/server/input.schema.ts index 336ade786..515e5b35f 100644 --- a/dlt-connector/src/server/input.schema.ts +++ b/dlt-connector/src/server/input.schema.ts @@ -2,18 +2,18 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' import { t } from 'elysia' import { hieroIdSchema, uuidv4Schema } from '../schemas/typeGuard.schema' -export const accountIdentifierUserSchema = t.Object({ +export const accountIdentifierUserTypeBoxSchema = t.Object({ communityTopicId: TypeBoxFromValibot(hieroIdSchema), userUuid: TypeBoxFromValibot(uuidv4Schema), accountNr: t.Number({ min: 0 }), }) // identifier for a gradido account created by transaction link / deferred transfer -export const accountIdentifierSeedSchema = t.Object({ +export const accountIdentifierSeedTypeBoxSchema = t.Object({ communityTopicId: TypeBoxFromValibot(hieroIdSchema), seed: TypeBoxFromValibot(uuidv4Schema), }) -export const existSchema = t.Object({ +export const existTypeBoxSchema = t.Object({ exists: t.Boolean(), }) From 617b1d6ad50eea8f9c35b3148e393efc1e6e6092 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 09:28:19 +0200 Subject: [PATCH 046/226] fix docker build and lint github workflows for dlt-connector --- .github/workflows/lint.yml | 15 ++- .github/workflows/test_dlt_connector.yml | 34 +++---- dlt-connector/Dockerfile | 119 +++++++++++++++++++++++ dlt-connector/bun.lock | 3 + dlt-connector/package.json | 1 + docker-compose.override.yml | 2 +- docker-compose.yml | 1 - 7 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 dlt-connector/Dockerfile diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1416b2e04..99124cf34 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,7 +25,6 @@ jobs: run: | cd ./config-schema biome ci . - echo $? echo "success=$([ $? -eq 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT - name: Lint - Shared id: shared @@ -57,6 +56,12 @@ jobs: cd ./dht-node biome ci . echo "success=$([ $? -eq 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT + - name: Lint - DLT Connector + id: dlt-connector + run: | + cd ./dlt-connector + biome ci . + echo "success=$([ $? -eq 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT - name: Lint - Federation id: federation run: | @@ -112,6 +117,14 @@ jobs: - name: Check result from previous step run: if [ "${{ needs.lint.outputs.dht-node }}" != "true" ]; then exit 1; fi + lint_dlt_connector: + name: Lint - DLT Connector + needs: lint + runs-on: ubuntu-latest + steps: + - name: Check result from previous step + run: if [ "${{ needs.lint.outputs.dlt-connector }}" != "true" ]; then exit 1; fi + lint_federation: name: Lint - Federation needs: lint diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index 7d3803065..da220cba7 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -30,27 +30,7 @@ jobs: uses: actions/checkout@v3 - name: Build 'test' image - run: | - docker build --target test -t "gradido/dlt-connector:test" -f dlt-connector/Dockerfile . - docker save "gradido/dlt-connector:test" > /tmp/dlt-connector.tar - - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: docker-dlt-connector-test - path: /tmp/dlt-connector.tar - - lint: - name: Lint - DLT Connector - if: needs.files-changed.outputs.dlt_connector == 'true' - needs: files-changed - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Lint - run: cd dlt-connector && yarn && yarn run lint + run: docker build --target test -t "gradido/dlt-connector:test" -f dlt-connector/Dockerfile . unit_test: name: Unit Tests - DLT Connector @@ -60,6 +40,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + + - name: install bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' - - name: DLT-Connector | Unit tests - run: cd dlt-connector && yarn && yarn test + - name: install dependencies + run: cd dlt-connector && bun install --frozen-lockfile + + - name: typecheck && unit test + run: cd dlt-connector && bun typecheck && bun test diff --git a/dlt-connector/Dockerfile b/dlt-connector/Dockerfile new file mode 100644 index 000000000..234c1df91 --- /dev/null +++ b/dlt-connector/Dockerfile @@ -0,0 +1,119 @@ +################################################################################## +# BASE ########################################################################### +################################################################################## +#FROM node:18.20.7-bookworm-slim as base +FROM oven/bun:1.3.0-slim as base +#FROM node:18.20.7-alpine3.21 as base +# change to alpine after sodium-native ship with native alpine build + +# ENVs (available in production aswell, can be overwritten by commandline or env file) +## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame +ENV DOCKER_WORKDIR="/app" +## We Cannot do `$(date -u +'%Y-%m-%dT%H:%M:%SZ')` here so we use unix timestamp=0 +ENV BUILD_DATE="1970-01-01T00:00:00.00Z" +## We cannot do $(npm run version).${BUILD_NUMBER} here so we default to 0.0.0.0 +ENV BUILD_VERSION="0.0.0.0" +## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000 +ENV BUILD_COMMIT="0000000" +## SET NODE_ENV +ENV NODE_ENV=production +## App relevant Envs +ENV PORT="4000" +## Timezone +ENV TZ=UTC + +# Labels +LABEL org.label-schema.build-date="${BUILD_DATE}" +LABEL org.label-schema.name="gradido:dlt-connector" +LABEL org.label-schema.description="Gradido DLT Connector" +LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md" +LABEL org.label-schema.url="https://gradido.net" +LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/dlt-connector" +LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}" +LABEL org.label-schema.vendor="Gradido Community" +LABEL org.label-schema.version="${BUILD_VERSION}" +LABEL org.label-schema.schema-version="1.0" +LABEL maintainer="support@gradido.net" + +# Install Additional Software +## install: git +#RUN apk --no-cache add git + + +# Settings +## Expose Container Port +EXPOSE ${PORT} + +## Workdir +RUN mkdir -p ${DOCKER_WORKDIR} +WORKDIR ${DOCKER_WORKDIR} + +################################################################################## +# BUN ############################################################################ +################################################################################## +#FROM base as bun-base + +#RUN apt update && apt install -y --no-install-recommends ca-certificates curl bash unzip +#COPY .bun-version .bun-version +#RUN apk update && apk add --no-cache curl tar bash +#RUN BUN_VERSION=$(cat .bun-version) && \ + # curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" +# Add bun's global bin directory to PATH +#ENV PATH="/root/.bun/bin:${PATH}" + +################################################################################## +# Development #################################################################### +################################################################################## +FROM base AS development + +# Run command +CMD /bin/sh -c "cd dlt-connector && bun install --no-cache --frozen-lockfile && bun dev" + +################################################################################## +# Basic Image with bun setup and project and source code ######################### +################################################################################## +FROM base as base-src +COPY --chown=app:app ./dlt-connector ./dlt-connector + +################################################################################## +# Build ########################################################################## +################################################################################## +FROM base-src as build + +RUN cd dlt-connector && bun install --no-cache --frozen-lockfile +RUN cd dlt-connector && bun typecheck && bun run build + +################################################################################## +# TEST ########################################################################### +################################################################################## +FROM build as test + +# Run command +CMD /bin/sh -c "cd dlt-connector && bun test" + +################################################################################## +# install only node modules needed for running bundle ############################ +################################################################################## +FROM base-src as production-node-modules + +COPY ./scripts ./scripts +# add node_modules from production_node_modules +RUN cd dlt-connector && bun install --production --frozen-lockfile --no-cache \ + && rm -rf /tmp/* ~/.cache node_modules/.cache \ + && ../scripts/clean-prebuilds.sh + +################################################################################## +# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) # +################################################################################## +FROM base as production + +# Copy "binary"-files from build image +COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/dlt-connector/build/index.js ./index.js +# add node_modules from production_node_modules +COPY --chown=app:app --from=production-node-modules ${DOCKER_WORKDIR}/dlt-connector/node_modules ./node_modules + +COPY ./dlt-connector/.env . +COPY ./dlt-connector/log4js-config.json . + +# Run command +CMD ["bun", "index.js"] diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 93b3943c1..7ea3a4eab 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -12,6 +12,7 @@ "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", + "@types/uuid": "^8.3.4", "dotenv": "^10.0.0", "elysia": "1.3.8", "graphql-request": "^7.2.0", @@ -271,6 +272,8 @@ "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], + "@types/uuid": ["@types/uuid@8.3.4", "", {}, "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="], + "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index bb7269703..7dc4e590d 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -25,6 +25,7 @@ "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", + "@types/uuid": "^8.3.4", "dotenv": "^10.0.0", "elysia": "1.3.8", "graphql-request": "^7.2.0", diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 8b19c4425..3d68512ce 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -104,7 +104,7 @@ services: - node_modules_dlt_connector:/app/node_modules - turbo_cache:/tmp/turbo # bind the local folder to the docker to allow live reload - - ./dlt-connector:/app + - .:/app ######################################################## # FEDERATION ########################################### diff --git a/docker-compose.yml b/docker-compose.yml index 3f11c6a07..aeaac0c60 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -172,7 +172,6 @@ services: - BUILD_VERSION - BUILD_COMMIT - NODE_ENV="production" - - DB_HOST=mariadb # Application only envs volumes: # : – mirror bidirectional path in local context with path in Docker container From 0525b144b72e89488bd65509ddd62eba7dedd89a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 10:38:40 +0200 Subject: [PATCH 047/226] remove not longer used stuff, fix lint workflow --- .github/workflows/lint.yml | 1 + .../graphql/resolver/TransactionResolver.ts | 2 - backend/src/index.ts | 4 -- backend/src/util/InterruptiveSleep.ts | 27 -------- backend/src/util/InterruptiveSleepManager.ts | 67 ------------------- 5 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 backend/src/util/InterruptiveSleep.ts delete mode 100644 backend/src/util/InterruptiveSleepManager.ts diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 99124cf34..df24c2b9f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,6 +12,7 @@ jobs: backend: ${{ steps.backend.outputs.success }} database: ${{ steps.database.outputs.success }} dht-node: ${{ steps.dht-node.outputs.success }} + dlt-connector: ${{ steps.dlt-connector.outputs.success }} federation: ${{ steps.federation.outputs.success }} steps: - name: Checkout diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 0bd77166c..4575a8b3e 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -185,8 +185,6 @@ export const executeTransaction = async ( await queryRunner.release() } - // notify dlt-connector loop for new work - // InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) await sendTransactionReceivedEmail({ firstName: recipient.firstName, lastName: recipient.lastName, diff --git a/backend/src/index.ts b/backend/src/index.ts index d7e883933..80d6d5d7e 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -20,10 +20,6 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) } }) - // task is running the whole time for transmitting transaction via dlt-connector to iota - // can be notified with InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY) - // that a new transaction or user was stored in db - // void sendTransactionsToDltConnector() void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } diff --git a/backend/src/util/InterruptiveSleep.ts b/backend/src/util/InterruptiveSleep.ts deleted file mode 100644 index 86afcf9b5..000000000 --- a/backend/src/util/InterruptiveSleep.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { delay } from 'core' - -/** - * Sleep, that can be interrupted - * call sleep only for msSteps and than check if interrupt was called - */ -export class InterruptiveSleep { - private interruptSleep = false - private msSteps = 10 - - constructor(msSteps: number) { - this.msSteps = msSteps - } - - public interrupt(): void { - this.interruptSleep = true - } - - public async sleep(ms: number): Promise { - let waited = 0 - this.interruptSleep = false - while (waited < ms && !this.interruptSleep) { - await delay(this.msSteps) - waited += this.msSteps - } - } -} diff --git a/backend/src/util/InterruptiveSleepManager.ts b/backend/src/util/InterruptiveSleepManager.ts deleted file mode 100644 index 246269623..000000000 --- a/backend/src/util/InterruptiveSleepManager.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { LogError } from '@/server/LogError' - -import { InterruptiveSleep } from './InterruptiveSleep' - -// Source: https://refactoring.guru/design-patterns/singleton/typescript/example -// and ../federation/client/FederationClientFactory.ts -/** - * Managing Instances of interruptive sleep it is inspired from conditions from c++ multithreading - * It is used for separate worker threads which will go to sleep after they haven't anything todo left, - * but with this Manager and InterruptiveSleep Object it sleeps only stepSize and check if something interrupted his sleep, - * so he can check for new work - */ -export const TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY = 'transmitToIota' - -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class InterruptiveSleepManager { - // eslint-disable-next-line no-use-before-define - private static instance: InterruptiveSleepManager - private interruptiveSleep: Map = new Map() - private stepSizeMilliseconds = 10 - - /** - * The Singleton's constructor should always be private to prevent direct - * construction calls with the `new` operator. - */ - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor() {} - - /** - * The static method that controls the access to the singleton instance. - * - * This implementation let you subclass the Singleton class while keeping - * just one instance of each subclass around. - */ - public static getInstance(): InterruptiveSleepManager { - if (!InterruptiveSleepManager.instance) { - InterruptiveSleepManager.instance = new InterruptiveSleepManager() - } - return InterruptiveSleepManager.instance - } - - /** - * only for new created InterruptiveSleepManager Entries! - * @param step size in ms in which new! InterruptiveSleepManager check if they where triggered - */ - public setStepSize(ms: number) { - this.stepSizeMilliseconds = ms - } - - public interrupt(key: string): void { - const interruptiveSleep = this.interruptiveSleep.get(key) - if (interruptiveSleep) { - interruptiveSleep.interrupt() - } - } - - public sleep(key: string, ms: number): Promise { - if (!this.interruptiveSleep.has(key)) { - this.interruptiveSleep.set(key, new InterruptiveSleep(this.stepSizeMilliseconds)) - } - const interruptiveSleep = this.interruptiveSleep.get(key) - if (!interruptiveSleep) { - throw new LogError('map entry not exist after setting it') - } - return interruptiveSleep.sleep(ms) - } -} From 5d4611f83fdf3491ccea4e9718244245c7642929 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 11:22:24 +0200 Subject: [PATCH 048/226] remove simple white space and order changes to make review less noisy --- backend/src/seeds/factory/user.ts | 1 + .../migrations/0091-add_dlt_users_table.ts | 30 -------- .../migrations/0092-merge_dlt_tables.ts | 37 ---------- .../migrations/0096-upgrade_dlt_tables.ts | 26 +++++++ database/src/AppDatabase.ts | 6 +- database/src/entity/Community.ts | 2 +- database/src/entity/Contribution.ts | 2 +- database/src/entity/Event.ts | 2 +- database/src/entity/User.ts | 2 +- database/src/logging/AbstractLogging.view.ts | 2 +- .../logging/PendingTransactionLogging.view.ts | 2 +- database/src/queries/communities.test.ts | 4 +- database/src/queries/communities.ts | 18 +++-- database/src/queries/index.ts | 4 +- .../src/queries/pendingTransactions.test.ts | 71 ++++++++++--------- database/src/queries/pendingTransactions.ts | 6 +- database/src/queries/transactionLinks.ts | 2 +- database/src/queries/user.test.ts | 38 +++++----- database/src/queries/user.ts | 17 ++--- .../src/seeds/factory/pendingTransaction.ts | 8 +-- database/src/seeds/factory/user.ts | 16 ++--- database/src/seeds/users/peter-lustig.ts | 2 +- database/src/util/index.ts | 2 +- dht-node/.env.dist | 2 +- 24 files changed, 129 insertions(+), 173 deletions(-) delete mode 100644 database/migration/migrations/0091-add_dlt_users_table.ts delete mode 100644 database/migration/migrations/0092-merge_dlt_tables.ts create mode 100644 database/migration/migrations/0096-upgrade_dlt_tables.ts diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 5da84c3b2..7904c61b2 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -13,6 +13,7 @@ export const userFactory = async ( user: UserInterface, ): Promise => { const { mutate } = client + const homeCom = await writeHomeCommunityEntry() // console.log('call createUser with', JSON.stringify(user, null, 2)) const response = await mutate({ mutation: createUser, variables: user }) diff --git a/database/migration/migrations/0091-add_dlt_users_table.ts b/database/migration/migrations/0091-add_dlt_users_table.ts deleted file mode 100644 index 95f5c2ca2..000000000 --- a/database/migration/migrations/0091-add_dlt_users_table.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(` - CREATE TABLE \`dlt_users\` ( - \`id\` int unsigned NOT NULL AUTO_INCREMENT, - \`user_id\` int(10) unsigned NOT NULL, - \`message_id\` varchar(64) NULL DEFAULT NULL, - \`verified\` tinyint(4) NOT NULL DEFAULT 0, - \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - \`verified_at\` datetime(3), - \`error\` text NULL DEFAULT NULL, - PRIMARY KEY (id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) - - await queryFn( - 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transactions_id` TO `transaction_id`;', - ) - await queryFn('ALTER TABLE `dlt_transactions` ADD COLUMN `error` text NULL DEFAULT NULL;') -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(`DROP TABLE \`dlt_users\`;`) - - await queryFn( - 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transaction_id` TO `transactions_id`;', - ) - await queryFn('ALTER TABLE `dlt_transactions` DROP COLUMN `error`;') -} diff --git a/database/migration/migrations/0092-merge_dlt_tables.ts b/database/migration/migrations/0092-merge_dlt_tables.ts deleted file mode 100644 index 70ee2d49e..000000000 --- a/database/migration/migrations/0092-merge_dlt_tables.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(`DROP TABLE \`dlt_users\`;`) - await queryFn(` - ALTER TABLE \`dlt_transactions\` - CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL, - ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, - ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`, - ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\` - ; - `) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(` - CREATE TABLE \`dlt_users\` ( - \`id\` int unsigned NOT NULL AUTO_INCREMENT, - \`user_id\` int(10) unsigned NOT NULL, - \`message_id\` varchar(64) NULL DEFAULT NULL, - \`verified\` tinyint(4) NOT NULL DEFAULT 0, - \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - \`verified_at\` datetime(3), - \`error\` text NULL DEFAULT NULL, - PRIMARY KEY (id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) - - await queryFn(` - ALTER TABLE \`dlt_transactions\` - CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NOT NULL, - DROP COLUMN \`user_id\`, - DROP COLUMN \`transaction_link_id\` - DROP COLUMN \`type_id\` - ; - `) -} diff --git a/database/migration/migrations/0096-upgrade_dlt_tables.ts b/database/migration/migrations/0096-upgrade_dlt_tables.ts new file mode 100644 index 000000000..849cdfc88 --- /dev/null +++ b/database/migration/migrations/0096-upgrade_dlt_tables.ts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(` + ALTER TABLE \`dlt_transactions\` + CHANGE \`transactions_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL, + ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, + ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`, + ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\`, + ADD \`error\` text NULL DEFAULT NULL AFTER \`verified_at\`, + ; + `) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(` + ALTER TABLE \`dlt_transactions\` + CHANGE \`transaction_id\` \`transactions_id\` INT(10) UNSIGNED NOT NULL, + DROP COLUMN \`user_id\`, + DROP COLUMN \`transaction_link_id\`, + DROP COLUMN \`type_id\`, + DROP COLUMN \`error\` + ; + `) +} diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts index e29a09965..c5275cb18 100644 --- a/database/src/AppDatabase.ts +++ b/database/src/AppDatabase.ts @@ -1,9 +1,9 @@ -import { getLogger } from 'log4js' import { DataSource as DBDataSource, FileLogger } from 'typeorm' +import { Migration, entities } from './entity' +import { getLogger } from 'log4js' import { latestDbVersion } from '.' import { CONFIG } from './config' import { LOG4JS_BASE_CATEGORY_NAME } from './config/const' -import { entities, Migration } from './entity' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.AppDatabase`) @@ -92,7 +92,7 @@ export class AppDatabase { public async destroy(): Promise { await this.dataSource?.destroy() } - + // ###################################### // private methods // ###################################### diff --git a/database/src/entity/Community.ts b/database/src/entity/Community.ts index af9cc1e7d..f6597306a 100644 --- a/database/src/entity/Community.ts +++ b/database/src/entity/Community.ts @@ -10,8 +10,8 @@ import { UpdateDateColumn, } from 'typeorm' import { FederatedCommunity } from './FederatedCommunity' -import { GeometryTransformer } from './transformer/GeometryTransformer' import { User } from './User' +import { GeometryTransformer } from './transformer/GeometryTransformer' @Entity('communities') export class Community extends BaseEntity { diff --git a/database/src/entity/Contribution.ts b/database/src/entity/Contribution.ts index a2f410e1d..976385263 100644 --- a/database/src/entity/Contribution.ts +++ b/database/src/entity/Contribution.ts @@ -12,8 +12,8 @@ import { } from 'typeorm' import { ContributionMessage } from './ContributionMessage' import { Transaction } from './Transaction' -import { DecimalTransformer } from './transformer/DecimalTransformer' import { User } from './User' +import { DecimalTransformer } from './transformer/DecimalTransformer' @Entity('contributions') export class Contribution extends BaseEntity { diff --git a/database/src/entity/Event.ts b/database/src/entity/Event.ts index b5ed77b21..9d17ffdeb 100644 --- a/database/src/entity/Event.ts +++ b/database/src/entity/Event.ts @@ -13,8 +13,8 @@ import { ContributionLink } from './ContributionLink' import { ContributionMessage } from './ContributionMessage' import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' -import { DecimalTransformer } from './transformer/DecimalTransformer' import { User } from './User' +import { DecimalTransformer } from './transformer/DecimalTransformer' @Entity('events') export class Event extends BaseEntity { diff --git a/database/src/entity/User.ts b/database/src/entity/User.ts index b2366b93c..6a40e9858 100644 --- a/database/src/entity/User.ts +++ b/database/src/entity/User.ts @@ -15,9 +15,9 @@ import { Contribution } from './Contribution' import { ContributionMessage } from './ContributionMessage' import { DltTransaction } from './DltTransaction' import { TransactionLink } from './TransactionLink' -import { GeometryTransformer } from './transformer/GeometryTransformer' import { UserContact } from './UserContact' import { UserRole } from './UserRole' +import { GeometryTransformer } from './transformer/GeometryTransformer' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { diff --git a/database/src/logging/AbstractLogging.view.ts b/database/src/logging/AbstractLogging.view.ts index 7e1616c65..f9a96ad5a 100644 --- a/database/src/logging/AbstractLogging.view.ts +++ b/database/src/logging/AbstractLogging.view.ts @@ -1,5 +1,5 @@ -import { Decimal } from 'decimal.js-light' import util from 'util' +import { Decimal } from 'decimal.js-light' export abstract class AbstractLoggingView { protected bufferStringFormat: BufferEncoding = 'hex' diff --git a/database/src/logging/PendingTransactionLogging.view.ts b/database/src/logging/PendingTransactionLogging.view.ts index 20e08e662..fad2d8f56 100644 --- a/database/src/logging/PendingTransactionLogging.view.ts +++ b/database/src/logging/PendingTransactionLogging.view.ts @@ -1,7 +1,7 @@ -import { PendingTransactionState } from 'shared' import { PendingTransaction, Transaction } from '../entity' import { AbstractLoggingView } from './AbstractLogging.view' import { TransactionLoggingView } from './TransactionLogging.view' +import { PendingTransactionState } from 'shared' export class PendingTransactionLoggingView extends AbstractLoggingView { public constructor(private self: PendingTransaction) { diff --git a/database/src/queries/communities.test.ts b/database/src/queries/communities.test.ts index b6a374cb9..b435c3649 100644 --- a/database/src/queries/communities.test.ts +++ b/database/src/queries/communities.test.ts @@ -1,7 +1,7 @@ -import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from '..' import { AppDatabase } from '../AppDatabase' import { getCommunityByPublicKeyOrFail, getHomeCommunity, getHomeCommunityWithFederatedCommunityOrFail, getReachableCommunities } from './communities' +import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest' import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community' import { Ed25519PublicKey } from 'shared' @@ -117,4 +117,4 @@ describe('community.queries', () => { expect(await getReachableCommunities(1000)).toHaveLength(0) }) }) -}) +}) \ No newline at end of file diff --git a/database/src/queries/communities.ts b/database/src/queries/communities.ts index 48f0080f0..fee69b27e 100644 --- a/database/src/queries/communities.ts +++ b/database/src/queries/communities.ts @@ -27,9 +27,7 @@ export async function getCommunityByUuid(communityUuid: string): Promise { +export function findWithCommunityIdentifier(communityIdentifier: string): FindOptionsWhere { const where: FindOptionsWhere = {} // pre filter identifier type to reduce db query complexity if (urlSchema.safeParse(communityIdentifier).success) { @@ -71,15 +69,15 @@ export async function getCommunityByPublicKeyOrFail(publicKey: Ed25519PublicKey) // home community and all federated communities which have been verified within the last authenticationTimeoutMs export async function getReachableCommunities( authenticationTimeoutMs: number, - order?: FindOptionsOrder, + order?: FindOptionsOrder ): Promise { return await DbCommunity.find({ - where: [ - { - authenticatedAt: Not(IsNull()), - federatedCommunities: { + where: [ + { + authenticatedAt: Not(IsNull()), + federatedCommunities: { verifiedAt: MoreThanOrEqual(new Date(Date.now() - authenticationTimeoutMs)), - }, + } }, { foreign: false }, ], @@ -94,4 +92,4 @@ export async function getNotReachableCommunities( where: { authenticatedAt: IsNull(), foreign: true }, order, }) -} +} \ No newline at end of file diff --git a/database/src/queries/index.ts b/database/src/queries/index.ts index 8241e010c..2cd0164ce 100644 --- a/database/src/queries/index.ts +++ b/database/src/queries/index.ts @@ -1,11 +1,11 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const' +export * from './user' export * from './communities' export * from './events' export * from './pendingTransactions' -export * from './transactionLinks' export * from './transactions' -export * from './user' +export * from './transactionLinks' export * from './communityHandshakes' export const LOG4JS_QUERIES_CATEGORY_NAME = `${LOG4JS_BASE_CATEGORY_NAME}.queries` diff --git a/database/src/queries/pendingTransactions.test.ts b/database/src/queries/pendingTransactions.test.ts index 1f7d0a3b7..5eab17136 100644 --- a/database/src/queries/pendingTransactions.test.ts +++ b/database/src/queries/pendingTransactions.test.ts @@ -1,22 +1,22 @@ -import Decimal from 'decimal.js-light' -import { PendingTransactionState } from 'shared' -import { v4 as uuidv4 } from 'uuid' -import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { - Community as DbCommunity, PendingTransaction as DbPendingTransaction, User as DbUser, UserContact as DbUserContact, + Community as DbCommunity, } from '..' +import { countOpenPendingTransactions } from './pendingTransactions' +import { PendingTransactionState } from 'shared' import { AppDatabase } from '../AppDatabase' -import { createCommunity } from '../seeds/community' -import { pendingTransactionFactory } from '../seeds/factory/pendingTransaction' import { userFactory } from '../seeds/factory/user' +import { pendingTransactionFactory } from '../seeds/factory/pendingTransaction' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' +import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' import { garrickOllivander } from '../seeds/users/garrick-ollivander' -import { peterLustig } from '../seeds/users/peter-lustig' -import { countOpenPendingTransactions } from './pendingTransactions' +import { describe, expect, it, beforeAll, afterAll } from 'vitest' +import { createCommunity } from '../seeds/community' +import { v4 as uuidv4 } from 'uuid' +import Decimal from 'decimal.js-light' const db = AppDatabase.getInstance() @@ -27,6 +27,7 @@ afterAll(async () => { await db.destroy() }) + describe('countOpenPendingTransactions', () => { let bibi: DbUser let peter: DbUser @@ -40,44 +41,45 @@ describe('countOpenPendingTransactions', () => { await createCommunity(false) - bibi = await userFactory(bibiBloxberg) + bibi = await userFactory(bibiBloxberg) peter = await userFactory(peterLustig) bob = await userFactory(bobBaumeister) garrick = await userFactory(garrickOllivander) // Bibi -> Peter await pendingTransactionFactory( - bibi, - peter, - new Decimal(10), - 'Bibi -> Peter new', - PendingTransactionState.NEW, + bibi, + peter, + new Decimal(10), + 'Bibi -> Peter new', + PendingTransactionState.NEW ) await pendingTransactionFactory( - bibi, - peter, - new Decimal(100.01), - 'Bibi -> Peter settled', - PendingTransactionState.SETTLED, + bibi, + peter, + new Decimal(100.01), + 'Bibi -> Peter settled', + PendingTransactionState.SETTLED ) // Peter -> Bibi await pendingTransactionFactory( - peter, - bibi, - new Decimal(12), - 'Peter -> Bibi new', - PendingTransactionState.NEW, + peter, + bibi, + new Decimal(12), + 'Peter -> Bibi new', + PendingTransactionState.NEW ) // Bob -> Peter await pendingTransactionFactory( - bob, - peter, - new Decimal(17.1), - 'Bob -> Peter new', - PendingTransactionState.NEW, + bob, + peter, + new Decimal(17.1), + 'Bob -> Peter new', + PendingTransactionState.NEW ) + }) it('should return 0 if called with empty array', async () => { const count = await countOpenPendingTransactions([]) @@ -102,20 +104,21 @@ describe('countOpenPendingTransactions', () => { it('peter and bob have one transaction together, peter two additional, should return 3', async () => { const count = await countOpenPendingTransactions([peter.gradidoID, bob.gradidoID]) expect(count).toBe(3) - }) - + }) + it('peter has three transactions, should return 3', async () => { const count = await countOpenPendingTransactions([peter.gradidoID]) expect(count).toBe(3) }) + it('bibi has two transactions, should return 2', async () => { const count = await countOpenPendingTransactions([bibi.gradidoID]) expect(count).toBe(2) - }) + }) it('bob has one transaction, should return 1', async () => { const count = await countOpenPendingTransactions([bob.gradidoID]) expect(count).toBe(1) - }) + }) }) diff --git a/database/src/queries/pendingTransactions.ts b/database/src/queries/pendingTransactions.ts index b6481af33..44bf63f82 100644 --- a/database/src/queries/pendingTransactions.ts +++ b/database/src/queries/pendingTransactions.ts @@ -1,6 +1,6 @@ -import { PendingTransactionState } from 'shared' -import { In } from 'typeorm' import { PendingTransaction as DbPendingTransaction } from '../entity' +import { In } from 'typeorm' +import { PendingTransactionState } from 'shared' /** * Counts the number of open pending transactions for the given users. @@ -15,4 +15,4 @@ export async function countOpenPendingTransactions(users: string[]): Promise { return await DbTransactionLink.findOneOrFail({ diff --git a/database/src/queries/user.test.ts b/database/src/queries/user.test.ts index 57096d264..23279770d 100644 --- a/database/src/queries/user.test.ts +++ b/database/src/queries/user.test.ts @@ -1,14 +1,14 @@ -import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' -import { clearLogs, getLogger, printLogs } from '../../../config-schema/test/testSetup.vitest' -import { Community as DbCommunity, User as DbUser, UserContact as DbUserContact } from '..' +import { User as DbUser, UserContact as DbUserContact, Community as DbCommunity } from '../entity' import { AppDatabase } from '../AppDatabase' -import { createCommunity } from '../seeds/community' +import { aliasExists, findUserByIdentifier } from './user' import { userFactory } from '../seeds/factory/user' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' -import { bobBaumeister } from '../seeds/users/bob-baumeister' +import { describe, expect, it, beforeAll, afterAll, beforeEach, } from 'vitest' +import { createCommunity } from '../seeds/community' import { peterLustig } from '../seeds/users/peter-lustig' +import { bobBaumeister } from '../seeds/users/bob-baumeister' +import { getLogger, printLogs, clearLogs } from '../../../config-schema/test/testSetup.vitest' import { LOG4JS_QUERIES_CATEGORY_NAME } from '.' -import { aliasExists, findUserByIdentifier } from './user' const db = AppDatabase.getInstance() const userIdentifierLoggerName = `${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier` @@ -26,9 +26,9 @@ describe('user.queries', () => { await DbUser.clear() await DbUserContact.clear() - const bibi = bibiBloxberg + const bibi = bibiBloxberg bibi.alias = 'b-b' - await userFactory(bibi) + await userFactory(bibi) }) it('should return true if alias exists', async () => { @@ -70,12 +70,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityUuid) expect(user).toMatchObject(userBibi) @@ -85,18 +85,18 @@ describe('user.queries', () => { expect(user).toBeNull() }) }) - + describe('communityIdentifier is community name', () => { it('userIdentifier is gradido id', async () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityName) expect(user).toMatchObject(userBibi) @@ -117,12 +117,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email) expect(user).toMatchObject(userBibi) @@ -130,12 +130,10 @@ describe('user.queries', () => { it('userIdentifier is unknown type', async () => { const user = await findUserByIdentifier('sa') printLogs() - expect(getLogger(userIdentifierLoggerName).warn).toHaveBeenCalledWith( - 'Unknown identifier type', - 'sa', - ) + expect(getLogger(userIdentifierLoggerName).warn).toHaveBeenCalledWith('Unknown identifier type', 'sa') expect(user).toBeNull() }) - }) + }) }) }) + diff --git a/database/src/queries/user.ts b/database/src/queries/user.ts index 9e7d84c27..c117c9ff8 100644 --- a/database/src/queries/user.ts +++ b/database/src/queries/user.ts @@ -1,7 +1,7 @@ -import { getLogger } from 'log4js' -import { aliasSchema, emailSchema, uuidv4Schema } from 'shared' import { Raw } from 'typeorm' import { User as DbUser, UserContact as DbUserContact } from '../entity' +import { aliasSchema, emailSchema, uuidv4Schema } from 'shared' +import { getLogger } from 'log4js' import { findWithCommunityIdentifier, LOG4JS_QUERIES_CATEGORY_NAME } from './index' export async function aliasExists(alias: string): Promise { @@ -32,8 +32,8 @@ export const findUserByIdentifier = async ( identifier: string, communityIdentifier?: string, ): Promise => { - const communityWhere = communityIdentifier - ? findWithCommunityIdentifier(communityIdentifier) + const communityWhere = communityIdentifier + ? findWithCommunityIdentifier(communityIdentifier) : undefined if (uuidv4Schema.safeParse(identifier).success) { @@ -52,12 +52,12 @@ export const findUserByIdentifier = async ( }, relations: { user: { community: true } }, }) - if (userContact) { + if (userContact) { // TODO: remove circular reference const user = userContact.user user.emailContact = userContact return user - } + } } else if (aliasSchema.safeParse(identifier).success) { return await DbUser.findOne({ where: { alias: identifier, community: communityWhere }, @@ -65,10 +65,7 @@ export const findUserByIdentifier = async ( }) } else { // should don't happen often, so we create only in the rare case a logger for it - getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn( - 'Unknown identifier type', - identifier, - ) + getLogger(`${LOG4JS_QUERIES_CATEGORY_NAME}.user.findUserByIdentifier`).warn('Unknown identifier type', identifier) } return null } diff --git a/database/src/seeds/factory/pendingTransaction.ts b/database/src/seeds/factory/pendingTransaction.ts index 75cb7c70e..64f10cee7 100644 --- a/database/src/seeds/factory/pendingTransaction.ts +++ b/database/src/seeds/factory/pendingTransaction.ts @@ -1,6 +1,6 @@ -import { Decimal } from 'decimal.js-light' -import { PendingTransactionState } from 'shared' import { PendingTransaction as DbPendingTransaction, User as DbUser } from '../..' +import { PendingTransactionState } from 'shared' +import { Decimal } from 'decimal.js-light' export async function pendingTransactionFactory( sender: DbUser, @@ -14,8 +14,8 @@ export async function pendingTransactionFactory( pendingTransaction.memo = memo pendingTransaction.amount = amount pendingTransaction.userId = sender.id - pendingTransaction.userGradidoID = sender.gradidoID - pendingTransaction.userCommunityUuid = sender.communityUuid! + pendingTransaction.userGradidoID = sender.gradidoID + pendingTransaction.userCommunityUuid = sender.communityUuid! pendingTransaction.linkedUserId = receiver.id pendingTransaction.linkedUserGradidoID = receiver.gradidoID pendingTransaction.linkedUserCommunityUuid = receiver.communityUuid! diff --git a/database/src/seeds/factory/user.ts b/database/src/seeds/factory/user.ts index 912cf00d0..369aa51a4 100644 --- a/database/src/seeds/factory/user.ts +++ b/database/src/seeds/factory/user.ts @@ -1,16 +1,16 @@ -import random from 'crypto-random-bigint' -import { OptInType, PasswordEncryptionType, UserContactType } from 'shared' -import { v4 } from 'uuid' -import { User, UserContact } from '../../entity' -import { getHomeCommunity } from '../../queries/communities' import { UserInterface } from '../users/UserInterface' +import { User, UserContact } from '../../entity' +import { v4 } from 'uuid' +import { UserContactType, OptInType, PasswordEncryptionType } from 'shared' +import { getHomeCommunity } from '../../queries/communities' +import random from 'crypto-random-bigint' export const userFactory = async (user: UserInterface): Promise => { let dbUserContact = new UserContact() dbUserContact.email = user.email ?? '' dbUserContact.type = UserContactType.USER_CONTACT_EMAIL - + let dbUser = new User() dbUser.firstName = user.firstName ?? '' dbUser.lastName = user.lastName ?? '' @@ -35,11 +35,11 @@ export const userFactory = async (user: UserInterface): Promise => { dbUser.community = homeCommunity dbUser.communityUuid = homeCommunity.communityUuid! } - // TODO: improve with cascade + // TODO: improve with cascade dbUser = await dbUser.save() dbUserContact.userId = dbUser.id dbUserContact = await dbUserContact.save() dbUser.emailId = dbUserContact.id dbUser.emailContact = dbUserContact return dbUser.save() -} +} \ No newline at end of file diff --git a/database/src/seeds/users/peter-lustig.ts b/database/src/seeds/users/peter-lustig.ts index ebd5235af..58b07fe99 100644 --- a/database/src/seeds/users/peter-lustig.ts +++ b/database/src/seeds/users/peter-lustig.ts @@ -7,5 +7,5 @@ export const peterLustig: UserInterface = { // description: 'Latzhose und Nickelbrille', createdAt: new Date('2020-11-25T10:48:43'), emailChecked: true, - language: 'de', + language: 'de' } diff --git a/database/src/util/index.ts b/database/src/util/index.ts index e2eb6c04e..d2fde2126 100644 --- a/database/src/util/index.ts +++ b/database/src/util/index.ts @@ -1,2 +1,2 @@ -export * from './TRANSACTION_LINK_LOCK' export * from './TRANSACTIONS_LOCK' +export * from './TRANSACTION_LINK_LOCK' diff --git a/dht-node/.env.dist b/dht-node/.env.dist index 1f4fca697..351bc251d 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -13,7 +13,7 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log # Federation # if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic FEDERATION_DHT_TOPIC=GRADIDO_HUB -FEDERATION_DHT_SEED=64ebcb0e3ad547848fed4197c6e1332f +# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f FEDERATION_COMMUNITY_URL=http://localhost # comma separated values, which apis should be announced FEDERATION_COMMUNITY_APIS=1_0 \ No newline at end of file From c2ca16bebcb7baf24b29400a6b87a82be25ef986 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 11:31:28 +0200 Subject: [PATCH 049/226] again --- backend/src/index.ts | 2 +- backend/src/seeds/factory/user.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index 80d6d5d7e..283554a9d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -20,7 +20,7 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) } }) - void startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) + await startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) } main().catch((e) => { diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 7904c61b2..3cae22f71 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -13,7 +13,7 @@ export const userFactory = async ( user: UserInterface, ): Promise => { const { mutate } = client - + const homeCom = await writeHomeCommunityEntry() // console.log('call createUser with', JSON.stringify(user, null, 2)) const response = await mutate({ mutation: createUser, variables: user }) From 2ac59f99cf15b97a626b44fae61fc7caa66a1726 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 11:36:30 +0200 Subject: [PATCH 050/226] again revert --- .github/workflows/lint.yml | 1 + .gitignore | 2 +- database/src/AppDatabase.ts | 1 + database/src/logging/AbstractLogging.view.ts | 1 + .../src/queries/pendingTransactions.test.ts | 16 ++++++++-------- database/src/queries/user.test.ts | 17 +++++++++-------- database/src/seeds/community.ts | 2 +- .../src/seeds/factory/pendingTransaction.ts | 10 +++++----- database/src/seeds/factory/user.ts | 2 +- 9 files changed, 28 insertions(+), 24 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index df24c2b9f..341053694 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,6 +26,7 @@ jobs: run: | cd ./config-schema biome ci . + echo $? echo "success=$([ $? -eq 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT - name: Lint - Shared id: shared diff --git a/.gitignore b/.gitignore index d98f0c163..d82288fbd 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ messages.pot nbproject .metadata /out/* -.env +/.env package-lock.json /deployment/bare_metal/.env /deployment/bare_metal/nginx/sites-available/gradido.conf diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts index c5275cb18..3096aaecd 100644 --- a/database/src/AppDatabase.ts +++ b/database/src/AppDatabase.ts @@ -1,5 +1,6 @@ import { DataSource as DBDataSource, FileLogger } from 'typeorm' import { Migration, entities } from './entity' + import { getLogger } from 'log4js' import { latestDbVersion } from '.' import { CONFIG } from './config' diff --git a/database/src/logging/AbstractLogging.view.ts b/database/src/logging/AbstractLogging.view.ts index f9a96ad5a..00fdd4703 100644 --- a/database/src/logging/AbstractLogging.view.ts +++ b/database/src/logging/AbstractLogging.view.ts @@ -1,4 +1,5 @@ import util from 'util' + import { Decimal } from 'decimal.js-light' export abstract class AbstractLoggingView { diff --git a/database/src/queries/pendingTransactions.test.ts b/database/src/queries/pendingTransactions.test.ts index 5eab17136..c59c312e4 100644 --- a/database/src/queries/pendingTransactions.test.ts +++ b/database/src/queries/pendingTransactions.test.ts @@ -1,8 +1,8 @@ -import { - PendingTransaction as DbPendingTransaction, - User as DbUser, - UserContact as DbUserContact, - Community as DbCommunity, +import { + PendingTransaction as DbPendingTransaction, + User as DbUser, + UserContact as DbUserContact, + Community as DbCommunity } from '..' import { countOpenPendingTransactions } from './pendingTransactions' import { PendingTransactionState } from 'shared' @@ -79,7 +79,7 @@ describe('countOpenPendingTransactions', () => { 'Bob -> Peter new', PendingTransactionState.NEW ) - + }) it('should return 0 if called with empty array', async () => { const count = await countOpenPendingTransactions([]) @@ -109,13 +109,13 @@ describe('countOpenPendingTransactions', () => { it('peter has three transactions, should return 3', async () => { const count = await countOpenPendingTransactions([peter.gradidoID]) expect(count).toBe(3) - }) + }) it('bibi has two transactions, should return 2', async () => { const count = await countOpenPendingTransactions([bibi.gradidoID]) expect(count).toBe(2) - }) + }) it('bob has one transaction, should return 1', async () => { const count = await countOpenPendingTransactions([bob.gradidoID]) diff --git a/database/src/queries/user.test.ts b/database/src/queries/user.test.ts index 23279770d..b653a5349 100644 --- a/database/src/queries/user.test.ts +++ b/database/src/queries/user.test.ts @@ -1,4 +1,4 @@ -import { User as DbUser, UserContact as DbUserContact, Community as DbCommunity } from '../entity' +import { User as DbUser, UserContact as DbUserContact, Community as DbCommunity } from '..' import { AppDatabase } from '../AppDatabase' import { aliasExists, findUserByIdentifier } from './user' import { userFactory } from '../seeds/factory/user' @@ -70,12 +70,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityUuid) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityUuid) expect(user).toMatchObject(userBibi) @@ -85,18 +85,18 @@ describe('user.queries', () => { expect(user).toBeNull() }) }) - + describe('communityIdentifier is community name', () => { it('userIdentifier is gradido id', async () => { const user = await findUserByIdentifier(userBibi.gradidoID, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias, communityName) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email, communityName) expect(user).toMatchObject(userBibi) @@ -117,12 +117,12 @@ describe('user.queries', () => { const user = await findUserByIdentifier(userBibi.gradidoID) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is alias', async () => { const user = await findUserByIdentifier(userBibi.alias) expect(user).toMatchObject(userBibi) }) - + it('userIdentifier is email', async () => { const user = await findUserByIdentifier(userBibi.emailContact.email) expect(user).toMatchObject(userBibi) @@ -137,3 +137,4 @@ describe('user.queries', () => { }) }) + diff --git a/database/src/seeds/community.ts b/database/src/seeds/community.ts index 000eea9ef..12a5bd67f 100644 --- a/database/src/seeds/community.ts +++ b/database/src/seeds/community.ts @@ -1,6 +1,6 @@ +import { Community, FederatedCommunity } from '../entity' import { randomBytes } from 'node:crypto' import { v4 as uuidv4 } from 'uuid' -import { Community, FederatedCommunity } from '../entity' /** * Creates a community. diff --git a/database/src/seeds/factory/pendingTransaction.ts b/database/src/seeds/factory/pendingTransaction.ts index 64f10cee7..2e8c7d256 100644 --- a/database/src/seeds/factory/pendingTransaction.ts +++ b/database/src/seeds/factory/pendingTransaction.ts @@ -1,4 +1,4 @@ -import { PendingTransaction as DbPendingTransaction, User as DbUser } from '../..' +import { User as DbUser, PendingTransaction as DbPendingTransaction } from '../..' import { PendingTransactionState } from 'shared' import { Decimal } from 'decimal.js-light' @@ -14,10 +14,10 @@ export async function pendingTransactionFactory( pendingTransaction.memo = memo pendingTransaction.amount = amount pendingTransaction.userId = sender.id - pendingTransaction.userGradidoID = sender.gradidoID - pendingTransaction.userCommunityUuid = sender.communityUuid! + pendingTransaction.userGradidoID = sender.gradidoID + pendingTransaction.userCommunityUuid = sender.communityUuid! pendingTransaction.linkedUserId = receiver.id - pendingTransaction.linkedUserGradidoID = receiver.gradidoID - pendingTransaction.linkedUserCommunityUuid = receiver.communityUuid! + pendingTransaction.linkedUserGradidoID = receiver.gradidoID + pendingTransaction.linkedUserCommunityUuid = receiver.communityUuid! await pendingTransaction.save() } diff --git a/database/src/seeds/factory/user.ts b/database/src/seeds/factory/user.ts index 369aa51a4..3772fe66d 100644 --- a/database/src/seeds/factory/user.ts +++ b/database/src/seeds/factory/user.ts @@ -10,7 +10,7 @@ export const userFactory = async (user: UserInterface): Promise => { dbUserContact.email = user.email ?? '' dbUserContact.type = UserContactType.USER_CONTACT_EMAIL - + let dbUser = new User() dbUser.firstName = user.firstName ?? '' dbUser.lastName = user.lastName ?? '' From 45321810f78e252a091703cc505483613bbc8ad5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 11:44:18 +0200 Subject: [PATCH 051/226] reduce review noise --- backend/src/graphql/resolver/TransactionResolver.ts | 9 +++++---- backend/src/graphql/resolver/UserResolver.test.ts | 8 +++++--- backend/src/graphql/resolver/UserResolver.ts | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 4575a8b3e..359e69b45 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -69,7 +69,7 @@ export const executeTransaction = async ( } try { - logger.info('executeTransaction', memo) + logger.info('executeTransaction', amount, memo, sender, recipient) if (await countOpenPendingTransactions([sender.gradidoID, recipient.gradidoID]) > 0) { throw new LogError( @@ -88,7 +88,7 @@ export const executeTransaction = async ( receivedCallDate, transactionLink, ) - logger.debug(`calculated balance=${sendBalance?.balance.toString()} decay=${sendBalance?.decay.decay.toString()} lastTransactionId=${sendBalance?.lastTransactionId}`) + logger.debug(`calculated Balance=${sendBalance}`) if (!sendBalance) { throw new LogError('User has not enough GDD or amount is < 0', sendBalance) } @@ -147,7 +147,7 @@ export const executeTransaction = async ( // Save linked transaction id for send transactionSend.linkedTransactionId = transactionReceive.id await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend) - logger.debug('send Transaction updated', new TransactionLoggingView(transactionSend).toJSON()) + logger.debug('send Transaction updated', transactionSend) if (transactionLink) { logger.info('transactionLink', transactionLink) @@ -161,8 +161,10 @@ export const executeTransaction = async ( } await queryRunner.commitTransaction() + logger.info(`commit Transaction successful...`) await EVENT_TRANSACTION_SEND(sender, recipient, transactionSend, transactionSend.amount) + await EVENT_TRANSACTION_RECEIVE( recipient, sender, @@ -184,7 +186,6 @@ export const executeTransaction = async ( } finally { await queryRunner.release() } - await sendTransactionReceivedEmail({ firstName: recipient.firstName, lastName: recipient.lastName, diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 35142e890..cee570c94 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -79,9 +79,11 @@ jest.mock('@/emails/sendEmailVariants', () => { return { __esModule: true, ...originalModule, - sendAccountActivationEmail: jest.fn(), - sendAccountMultiRegistrationEmail: jest.fn(), - sendResetPasswordEmail: jest.fn(), + sendAccountActivationEmail: jest.fn((a) => originalModule.sendAccountActivationEmail(a)), + sendAccountMultiRegistrationEmail: jest.fn((a) => + originalModule.sendAccountMultiRegistrationEmail(a), + ), + sendResetPasswordEmail: jest.fn((a) => originalModule.sendResetPasswordEmail(a)), } }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 2398a3a95..70b1642a8 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -25,7 +25,7 @@ import { Root, } from 'type-graphql' import { IRestResponse } from 'typed-rest-client' -import { EntityNotFoundError, In, Point } from 'typeorm' +import { EntityManager, EntityNotFoundError, In, Point } from 'typeorm' import { v4 as uuidv4 } from 'uuid' import { UserArgs } from '@arg//UserArgs' From 6caddf05c0bbf10758b149972516e616014f3ebf Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 12:16:56 +0200 Subject: [PATCH 052/226] fix migration mysql --- database/migration/migrations/0096-upgrade_dlt_tables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migration/migrations/0096-upgrade_dlt_tables.ts b/database/migration/migrations/0096-upgrade_dlt_tables.ts index 849cdfc88..8ee2550ca 100644 --- a/database/migration/migrations/0096-upgrade_dlt_tables.ts +++ b/database/migration/migrations/0096-upgrade_dlt_tables.ts @@ -8,7 +8,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`, ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`, ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\`, - ADD \`error\` text NULL DEFAULT NULL AFTER \`verified_at\`, + ADD \`error\` text NULL DEFAULT NULL AFTER \`verified_at\` ; `) } From 5f36c197f65c657a74490e843591195588075ccc Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 12:41:38 +0200 Subject: [PATCH 053/226] fix test --- .github/workflows/test_dlt_connector.yml | 10 ++++++++-- dlt-connector/.gitignore | 9 +++++++++ dlt-connector/src/config/schema.ts | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 dlt-connector/.gitignore diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index da220cba7..4e1b660e8 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v3 - name: Build 'test' image - run: docker build --target test -t "gradido/dlt-connector:test" -f dlt-connector/Dockerfile . + run: docker build --target production -t "gradido/dlt-connector:productionTest" -f dlt-connector/Dockerfile . unit_test: name: Unit Tests - DLT Connector @@ -50,4 +50,10 @@ jobs: run: cd dlt-connector && bun install --frozen-lockfile - name: typecheck && unit test - run: cd dlt-connector && bun typecheck && bun test + run: | + GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$(openssl rand -hex 16) + GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$(openssl rand -hex 16) + HOME_COMMUNITY_SEED=$(openssl rand -hex 32) + HIERO_OPERATOR_KEY=$(openssl rand -hex 32) + HIERO_OPERATOR_ID="0.0.2" + cd dlt-connector && bun typecheck && bun test diff --git a/dlt-connector/.gitignore b/dlt-connector/.gitignore new file mode 100644 index 000000000..5435dd5ff --- /dev/null +++ b/dlt-connector/.gitignore @@ -0,0 +1,9 @@ +/node_modules/ +/.env +/.env.bak +/build/ +/locales/ +package-json.lock +coverage +# emacs +*~ diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 3dfe3cbe9..6c364a3ef 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -20,7 +20,7 @@ export const configSchema = v.object({ ), '6010', ), - JWT_SECRET: v.pipe( + JWT_SECRET: v.optional(v.pipe( v.string('The JWT secret for connecting to the backend'), v.custom((input: unknown): boolean => { if (process.env.NODE_ENV === 'production' && input === 'secret123') { @@ -28,7 +28,7 @@ export const configSchema = v.object({ } return true }, "Shouldn't use default value in production"), - ), + ), 'secret123'), GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: hexSchema, GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: hex16Schema, HOME_COMMUNITY_SEED: v.pipe( From 6da30e9fd2c6be42db23b38314445fff1c33d75a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 12:45:08 +0200 Subject: [PATCH 054/226] again fix --- .github/workflows/test_dlt_connector.yml | 11 +++++++++++ dlt-connector/src/config/schema.ts | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index 4e1b660e8..bfde9cc8b 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -28,6 +28,17 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + + - name: create .env + run: | + cd dlt-connector + cat < .env + GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$(openssl rand -hex 16) + GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$(openssl rand -hex 16) + HOME_COMMUNITY_SEED=$(openssl rand -hex 32) + HIERO_OPERATOR_KEY=$(openssl rand -hex 32) + HIERO_OPERATOR_ID="0.0.2" + EOF - name: Build 'test' image run: docker build --target production -t "gradido/dlt-connector:productionTest" -f dlt-connector/Dockerfile . diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 6c364a3ef..08eeb2b80 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -20,15 +20,18 @@ export const configSchema = v.object({ ), '6010', ), - JWT_SECRET: v.optional(v.pipe( - v.string('The JWT secret for connecting to the backend'), - v.custom((input: unknown): boolean => { - if (process.env.NODE_ENV === 'production' && input === 'secret123') { - return false - } - return true - }, "Shouldn't use default value in production"), - ), 'secret123'), + JWT_SECRET: v.optional( + v.pipe( + v.string('The JWT secret for connecting to the backend'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === 'secret123') { + return false + } + return true + }, "Shouldn't use default value in production"), + ), + 'secret123', + ), GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET: hexSchema, GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY: hex16Schema, HOME_COMMUNITY_SEED: v.pipe( From 19c8bb8d446d285c34ed521b3fa5e57dab705bba Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 12:50:05 +0200 Subject: [PATCH 055/226] add export --- .github/workflows/test_dlt_connector.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index bfde9cc8b..3ba43063f 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -62,9 +62,10 @@ jobs: - name: typecheck && unit test run: | - GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$(openssl rand -hex 16) - GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$(openssl rand -hex 16) - HOME_COMMUNITY_SEED=$(openssl rand -hex 32) - HIERO_OPERATOR_KEY=$(openssl rand -hex 32) - HIERO_OPERATOR_ID="0.0.2" - cd dlt-connector && bun typecheck && bun test + export GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$(openssl rand -hex 16) + export GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$(openssl rand -hex 16) + export HOME_COMMUNITY_SEED=$(openssl rand -hex 32) + export HIERO_OPERATOR_KEY=$(openssl rand -hex 32) + export HIERO_OPERATOR_ID="0.0.2" + cd dlt-connector && bun typecheck && bun test + From 04e0075679cdade8b68a599f8a0f79cfe534d33e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 13:26:43 +0200 Subject: [PATCH 056/226] finetuning of structure --- .../src/{ => cache}/KeyPairCacheManager.ts | 5 ++- .../client/GradidoNode/GradidoNodeClient.ts | 24 +++++------ .../client/GradidoNode/input.schema.test.ts | 14 +++--- .../src/client/backend/BackendClient.ts | 8 +--- .../src/client/backend/community.schema.ts | 43 ------------------- dlt-connector/src/client/backend/graphql.ts | 30 +++++++++++++ ...y.schema.test.ts => output.schema.test.ts} | 2 +- .../src/client/backend/output.schema.ts | 14 ++++++ dlt-connector/src/client/hiero/HieroClient.ts | 10 ++--- dlt-connector/src/config/index.ts | 8 ++-- dlt-connector/src/index.ts | 6 +-- .../ResolveKeyPair.context.test.ts | 12 +++--- .../resolveKeyPair/ResolveKeyPair.context.ts | 3 +- .../sendToHiero/CreationTransaction.role.ts | 2 +- .../DeferredTransferTransaction.role.ts | 6 +-- .../RedeemDeferredTransferTransaction.role.ts | 4 +- .../RegisterAddressTransaction.role.test.ts | 6 +-- .../RegisterAddressTransaction.role.ts | 6 +-- .../sendToHiero/TransferTransaction.role.ts | 4 +- dlt-connector/src/schemas/base.schema.ts | 2 - .../src/schemas/transaction.schema.test.ts | 28 ++++++------ dlt-connector/src/server/index.test.ts | 6 +-- 22 files changed, 118 insertions(+), 125 deletions(-) rename dlt-connector/src/{ => cache}/KeyPairCacheManager.ts (92%) delete mode 100644 dlt-connector/src/client/backend/community.schema.ts create mode 100644 dlt-connector/src/client/backend/graphql.ts rename dlt-connector/src/client/backend/{community.schema.test.ts => output.schema.test.ts} (93%) create mode 100644 dlt-connector/src/client/backend/output.schema.ts delete mode 100644 dlt-connector/src/schemas/base.schema.ts diff --git a/dlt-connector/src/KeyPairCacheManager.ts b/dlt-connector/src/cache/KeyPairCacheManager.ts similarity index 92% rename from dlt-connector/src/KeyPairCacheManager.ts rename to dlt-connector/src/cache/KeyPairCacheManager.ts index a74780471..8d7c3bf56 100644 --- a/dlt-connector/src/KeyPairCacheManager.ts +++ b/dlt-connector/src/cache/KeyPairCacheManager.ts @@ -1,11 +1,12 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from './config/const' -import { HieroId } from './schemas/typeGuard.schema' +import { LOG4JS_BASE_CATEGORY } from '../config/const' +import { HieroId } from '../schemas/typeGuard.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts +// TODO: TTL (time to live) based, maybe even optional use of redis /** * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index c7f9d2fb7..9f43b95ef 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -2,7 +2,7 @@ import { ConfirmedTransaction } from 'gradido-blockchain-js' import JsonRpcClient from 'jsonrpc-ts-client' import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrpc' import { getLogger, Logger } from 'log4js' -import { parse } from 'valibot' +import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Uuidv4Hash } from '../../data/Uuidv4Hash' @@ -61,13 +61,13 @@ export class GradidoNodeClient { transactionIdentifier: TransactionIdentifierInput, ): Promise { const parameter = { - ...parse(transactionIdentifierSchema, transactionIdentifier), + ...v.parse(transactionIdentifierSchema, transactionIdentifier), format: 'base64', } const response = await this.rpcCall<{ transaction: string }>('getTransaction', parameter) if (response.isSuccess()) { // this.logger.debug('result: ', response.result.transaction) - return parse(confirmedTransactionSchema, response.result.transaction) + return v.parse(confirmedTransactionSchema, response.result.transaction) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { @@ -92,7 +92,7 @@ export class GradidoNodeClient { } const response = await this.rpcCall<{ transaction: string }>('getLastTransaction', parameter) if (response.isSuccess()) { - return parse(confirmedTransactionSchema, response.result.transaction) + return v.parse(confirmedTransactionSchema, response.result.transaction) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { @@ -121,7 +121,7 @@ export class GradidoNodeClient { */ public async getTransactions(input: TransactionsRangeInput): Promise { const parameter = { - ...parse(transactionsRangeSchema, input), + ...v.parse(transactionsRangeSchema, input), format: 'base64', } const result = await this.rpcCallResolved<{ transactions: string[] }>( @@ -129,7 +129,7 @@ export class GradidoNodeClient { parameter, ) return result.transactions.map((transactionBase64) => - parse(confirmedTransactionSchema, transactionBase64), + v.parse(confirmedTransactionSchema, transactionBase64), ) } @@ -146,8 +146,8 @@ export class GradidoNodeClient { pubkey: Hex32Input, ): Promise { const parameter = { - ...parse(transactionsRangeSchema, transactionRange), - pubkey: parse(hex32Schema, pubkey), + ...v.parse(transactionsRangeSchema, transactionRange), + pubkey: v.parse(hex32Schema, pubkey), format: 'base64', } const response = await this.rpcCallResolved<{ transactions: string[] }>( @@ -155,7 +155,7 @@ export class GradidoNodeClient { parameter, ) return response.transactions.map((transactionBase64) => - parse(confirmedTransactionSchema, transactionBase64), + v.parse(confirmedTransactionSchema, transactionBase64), ) } @@ -172,14 +172,14 @@ export class GradidoNodeClient { public async getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise { const parameter = { - pubkey: parse(hex32Schema, pubkey), + pubkey: v.parse(hex32Schema, pubkey), topic: hieroTopic, } const response = await this.rpcCallResolved<{ addressType: string }>( 'getAddressType', parameter, ) - return parse(addressTypeSchema, response.addressType) + return v.parse(addressTypeSchema, response.addressType) } /** @@ -204,7 +204,7 @@ export class GradidoNodeClient { ) if (response.isSuccess()) { this.logger.info(`call findUserByNameHash, used ${response.result.timeUsed}`) - return parse(hex32Schema, response.result.pubkey) + return v.parse(hex32Schema, response.result.pubkey) } if ( response.isError() && diff --git a/dlt-connector/src/client/GradidoNode/input.schema.test.ts b/dlt-connector/src/client/GradidoNode/input.schema.test.ts index b4c86326e..fbe63dabb 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.test.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.test.ts @@ -1,5 +1,5 @@ import { beforeAll, describe, expect, it } from 'bun:test' -import { parse } from 'valibot' +import * as v from 'valibot' import { HieroId, HieroTransactionIdString, @@ -12,14 +12,14 @@ let topic: HieroId const topicString = '0.0.261' let hieroTransactionId: HieroTransactionIdString beforeAll(() => { - topic = parse(hieroIdSchema, topicString) - hieroTransactionId = parse(hieroTransactionIdStringSchema, '0.0.261-1755348116-1281621') + topic = v.parse(hieroIdSchema, topicString) + hieroTransactionId = v.parse(hieroTransactionIdStringSchema, '0.0.261-1755348116-1281621') }) describe('transactionIdentifierSchema ', () => { it('valid, transaction identified by transactionNr and topic', () => { expect( - parse(transactionIdentifierSchema, { + v.parse(transactionIdentifierSchema, { transactionId: 1, topic: topicString, }), @@ -31,7 +31,7 @@ describe('transactionIdentifierSchema ', () => { }) it('valid, transaction identified by hieroTransactionId and topic', () => { expect( - parse(transactionIdentifierSchema, { + v.parse(transactionIdentifierSchema, { hieroTransactionId: '0.0.261-1755348116-1281621', topic: topicString, }), @@ -42,7 +42,7 @@ describe('transactionIdentifierSchema ', () => { }) it('invalid, missing topic', () => { expect(() => - parse(transactionIdentifierSchema, { + v.parse(transactionIdentifierSchema, { transactionId: 1, hieroTransactionId: '0.0.261-1755348116-1281621', }), @@ -50,7 +50,7 @@ describe('transactionIdentifierSchema ', () => { }) it('invalid, transactionNr and iotaMessageId set', () => { expect(() => - parse(transactionIdentifierSchema, { + v.parse(transactionIdentifierSchema, { transactionId: 1, hieroTransactionId: '0.0.261-1755348116-1281621', topic, diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 2d587a4d8..d5cc3be9e 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -5,12 +5,8 @@ import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' -import { - type Community, - communitySchema, - homeCommunityGraphqlQuery, - setHomeCommunityTopicId, -} from './community.schema' +import { homeCommunityGraphqlQuery, setHomeCommunityTopicId } from './graphql' +import { type Community, communitySchema } from './output.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example // and ../federation/client/FederationClientFactory.ts diff --git a/dlt-connector/src/client/backend/community.schema.ts b/dlt-connector/src/client/backend/community.schema.ts deleted file mode 100644 index a37159bc5..000000000 --- a/dlt-connector/src/client/backend/community.schema.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { gql } from 'graphql-request' -import * as v from 'valibot' -import { dateSchema } from '../../schemas/typeConverter.schema' -import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' - -/** - * Schema Definitions for graphql response - */ -export const communitySchema = v.object({ - uuid: uuidv4Schema, - name: v.string('expect string type'), - hieroTopicId: v.nullish(hieroIdSchema), - foreign: v.boolean('expect boolean type'), - creationDate: dateSchema, -}) - -export type CommunityInput = v.InferInput -export type Community = v.InferOutput - -// graphql query for getting home community in tune with community schema -export const homeCommunityGraphqlQuery = gql` - query { - homeCommunity { - uuid - name - hieroTopicId - foreign - creationDate - } - } -` - -export const setHomeCommunityTopicId = gql` - mutation ($uuid: String!, $hieroTopicId: String){ - updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { - uuid - name - hieroTopicId - foreign - creationDate - } - } -` diff --git a/dlt-connector/src/client/backend/graphql.ts b/dlt-connector/src/client/backend/graphql.ts new file mode 100644 index 000000000..11d1eb099 --- /dev/null +++ b/dlt-connector/src/client/backend/graphql.ts @@ -0,0 +1,30 @@ +import { gql } from 'graphql-request' + +/** + * Schema Definitions for graphql requests + */ + +// graphql query for getting home community in tune with community schema +export const homeCommunityGraphqlQuery = gql` + query { + homeCommunity { + uuid + name + hieroTopicId + foreign + creationDate + } + } +` + +export const setHomeCommunityTopicId = gql` + mutation ($uuid: String!, $hieroTopicId: String){ + updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { + uuid + name + hieroTopicId + foreign + creationDate + } + } +` diff --git a/dlt-connector/src/client/backend/community.schema.test.ts b/dlt-connector/src/client/backend/output.schema.test.ts similarity index 93% rename from dlt-connector/src/client/backend/community.schema.test.ts rename to dlt-connector/src/client/backend/output.schema.test.ts index 180ab9d5a..6697bd210 100644 --- a/dlt-connector/src/client/backend/community.schema.test.ts +++ b/dlt-connector/src/client/backend/output.schema.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'bun:test' import * as v from 'valibot' import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' -import { communitySchema } from './community.schema' +import { communitySchema } from './output.schema' describe('community.schema', () => { it('community', () => { diff --git a/dlt-connector/src/client/backend/output.schema.ts b/dlt-connector/src/client/backend/output.schema.ts new file mode 100644 index 000000000..86c658fe8 --- /dev/null +++ b/dlt-connector/src/client/backend/output.schema.ts @@ -0,0 +1,14 @@ +import * as v from 'valibot' +import { dateSchema } from '../../schemas/typeConverter.schema' +import { hieroIdSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' + +export const communitySchema = v.object({ + uuid: uuidv4Schema, + name: v.string('expect string type'), + hieroTopicId: v.nullish(hieroIdSchema), + foreign: v.boolean('expect boolean type'), + creationDate: dateSchema, +}) + +export type CommunityInput = v.InferInput +export type Community = v.InferOutput diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index a22e8f27b..e48eefc92 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -10,13 +10,11 @@ import { TopicMessageSubmitTransaction, TopicUpdateTransaction, TransactionId, - TransactionReceipt, - TransactionResponse, Wallet, } from '@hashgraph/sdk' -import { GradidoTransaction, HieroTopicId } from 'gradido-blockchain-js' +import { GradidoTransaction } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' -import { parse } from 'valibot' +import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' @@ -139,7 +137,7 @@ export class HieroClient { } this.logger.debug(`topic sequence number: ${info.sequenceNumber.toNumber()}`) // this.logger.debug(JSON.stringify(info, null, 2)) - return parse(topicInfoSchema, { + return v.parse(topicInfoSchema, { topicId: topicId.toString(), sequenceNumber: info.sequenceNumber.toNumber(), expirationTime: info.expirationTime?.toDate(), @@ -165,7 +163,7 @@ export class HieroClient { this.logger.addContext('topicId', createReceipt.topicId?.toString()) const record = await createResponse.getRecordWithSigner(this.wallet) this.logger.info(`topic created, cost: ${record.transactionFee.toString()}`) - return parse(hieroIdSchema, createReceipt.topicId?.toString()) + return v.parse(hieroIdSchema, createReceipt.topicId?.toString()) } public async updateTopic(topicId: HieroId): Promise { diff --git a/dlt-connector/src/config/index.ts b/dlt-connector/src/config/index.ts index 10e3cea39..044cb610d 100644 --- a/dlt-connector/src/config/index.ts +++ b/dlt-connector/src/config/index.ts @@ -1,16 +1,16 @@ import dotenv from 'dotenv' -import { InferOutput, parse, ValiError } from 'valibot' +import * as v from 'valibot' import { configSchema } from './schema' dotenv.config() -type ConfigOutput = InferOutput +type ConfigOutput = v.InferOutput let config: ConfigOutput try { - config = parse(configSchema, process.env) + config = v.parse(configSchema, process.env) } catch (error) { - if (error instanceof ValiError) { + if (error instanceof v.ValiError) { // biome-ignore lint/suspicious/noConsole: need to parse config before initializing logger console.error( `${error.issues[0].path[0].key}: ${error.message} received: ${error.issues[0].received}`, diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 2a681d300..22ae267e2 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -2,14 +2,14 @@ import { readFileSync } from 'node:fs' import { Elysia } from 'elysia' import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { configure, getLogger, Logger } from 'log4js' -import { parse } from 'valibot' +import * as v from 'valibot' +import { KeyPairCacheManager } from './cache/KeyPairCacheManager' import { BackendClient } from './client/backend/BackendClient' import { GradidoNodeClient } from './client/GradidoNode/GradidoNodeClient' import { HieroClient } from './client/hiero/HieroClient' import { CONFIG } from './config' import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' import { SendToHieroContext } from './interactions/sendToHiero/SendToHiero.context' -import { KeyPairCacheManager } from './KeyPairCacheManager' import { Community, communitySchema } from './schemas/transaction.schema' import { appRoutes } from './server' import { isPortOpenRetry } from './utils/network' @@ -133,7 +133,7 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): logger.info(`home community topic: ${homeCommunity.hieroTopicId}`) logger.info(`gradido node server: ${CONFIG.NODE_SERVER_URL}`) logger.info(`gradido backend server: ${CONFIG.BACKEND_SERVER_URL}`) - return parse(communitySchema, homeCommunity) + return v.parse(communitySchema, homeCommunity) } main().catch((e) => { diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts index 6d208eaff..16a444cd8 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.test.ts @@ -1,8 +1,8 @@ import { afterAll, beforeAll, describe, expect, it, mock } from 'bun:test' import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairCacheManager } from '../../KeyPairCacheManager' import { identifierKeyPairSchema } from '../../schemas/account.schema' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { ResolveKeyPair } from './ResolveKeyPair.context' @@ -41,11 +41,11 @@ afterAll(() => { describe('KeyPairCalculation', () => { beforeAll(() => { - KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(v.parse(hieroIdSchema, '0.0.21732')) }) it('community key pair', async () => { const identifier = new KeyPairIdentifierLogic( - parse(identifierKeyPairSchema, { communityTopicId: topicId }), + v.parse(identifierKeyPairSchema, { communityTopicId: topicId }), ) const keyPair = await ResolveKeyPair(identifier) expect(keyPair.getPublicKey()?.convertToHex()).toBe( @@ -54,7 +54,7 @@ describe('KeyPairCalculation', () => { }) it('user key pair', async () => { const identifier = new KeyPairIdentifierLogic( - parse(identifierKeyPairSchema, { + v.parse(identifierKeyPairSchema, { communityTopicId: topicId, account: { userUuid }, }), @@ -69,7 +69,7 @@ describe('KeyPairCalculation', () => { it('account key pair', async () => { const identifier = new KeyPairIdentifierLogic( - parse(identifierKeyPairSchema, { + v.parse(identifierKeyPairSchema, { communityTopicId: topicId, account: { userUuid, accountNr: 1 }, }), diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 2fbdd906c..406463c4c 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -1,7 +1,6 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' - +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairCacheManager } from '../../KeyPairCacheManager' import { AccountKeyPairRole } from './AccountKeyPair.role' import { ForeignCommunityKeyPairRole } from './ForeignCommunityKeyPair.role' import { HomeCommunityKeyPairRole } from './HomeCommunityKeyPair.role' diff --git a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts index d11b031e2..4b0f7aefd 100644 --- a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts @@ -5,8 +5,8 @@ import { TransferAmount, } from 'gradido-blockchain-js' import { parse } from 'valibot' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairCacheManager } from '../../KeyPairCacheManager' import { CreationTransaction, creationTransactionSchema, diff --git a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts index ac0b924f6..95459a8b6 100644 --- a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts @@ -5,7 +5,7 @@ import { GradidoTransfer, TransferAmount, } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { DeferredTransferTransaction, @@ -21,8 +21,8 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { private readonly deferredTransferTransaction: DeferredTransferTransaction constructor(transaction: Transaction) { super() - this.deferredTransferTransaction = parse(deferredTransferTransactionSchema, transaction) - this.seed = parse(identifierSeedSchema, this.deferredTransferTransaction.linkedUser.seed) + this.deferredTransferTransaction = v.parse(deferredTransferTransactionSchema, transaction) + this.seed = v.parse(identifierSeedSchema, this.deferredTransferTransaction.linkedUser.seed) } getSenderCommunityTopicId(): HieroId { diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 76d621762..626712404 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,5 +1,5 @@ import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { @@ -17,7 +17,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo private readonly redeemDeferredTransferTransaction: RedeemDeferredTransferTransaction constructor(transaction: Transaction) { super() - this.redeemDeferredTransferTransaction = parse( + this.redeemDeferredTransferTransaction = v.parse( redeemDeferredTransferTransactionSchema, transaction, ) diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index 968a3c992..ef896e1e8 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'bun:test' import { InteractionToJson, InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' import { transactionSchema } from '../../schemas/transaction.schema' import { hieroIdSchema } from '../../schemas/typeGuard.schema' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' @@ -22,10 +22,10 @@ const transaction = { describe('RegisterAddressTransaction.role', () => { it('get correct prepared builder', async () => { const registerAddressTransactionRole = new RegisterAddressTransactionRole( - parse(transactionSchema, transaction), + v.parse(transactionSchema, transaction), ) expect(registerAddressTransactionRole.getSenderCommunityTopicId()).toBe( - parse(hieroIdSchema, '0.0.21732'), + v.parse(hieroIdSchema, '0.0.21732'), ) expect(() => registerAddressTransactionRole.getRecipientCommunityTopicId()).toThrow() const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index 8f0f50e6b..acb40975c 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -1,5 +1,5 @@ import { AddressType, GradidoTransactionBuilder } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { Uuidv4Hash } from '../../data/Uuidv4Hash' import { @@ -20,8 +20,8 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { private readonly account: IdentifierCommunityAccount constructor(input: Transaction) { super() - this.registerAddressTransaction = parse(registerAddressTransactionSchema, input) - this.account = parse(identifierCommunityAccountSchema, input.user.account) + this.registerAddressTransaction = v.parse(registerAddressTransactionSchema, input) + this.account = v.parse(identifierCommunityAccountSchema, input.user.account) } getSenderCommunityTopicId(): HieroId { diff --git a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts index 03d1480b9..f0a1314cb 100644 --- a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts @@ -4,7 +4,7 @@ import { GradidoTransactionBuilder, TransferAmount, } from 'gradido-blockchain-js' -import { parse } from 'valibot' +import * as v from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { Transaction, @@ -19,7 +19,7 @@ export class TransferTransactionRole extends AbstractTransactionRole { private transferTransaction: TransferTransaction constructor(input: Transaction) { super() - this.transferTransaction = parse(transferTransactionSchema, input) + this.transferTransaction = v.parse(transferTransactionSchema, input) } getSenderCommunityTopicId(): HieroId { diff --git a/dlt-connector/src/schemas/base.schema.ts b/dlt-connector/src/schemas/base.schema.ts deleted file mode 100644 index da3dbfdfa..000000000 --- a/dlt-connector/src/schemas/base.schema.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { MemoryBlock } from 'gradido-blockchain-js' -import * as v from 'valibot' diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index de87cacfd..533cd35b9 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -4,7 +4,7 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' import { randomBytes } from 'crypto' import { AddressType_COMMUNITY_HUMAN } from 'gradido-blockchain-js' import { v4 as uuidv4 } from 'uuid' -import { parse } from 'valibot' +import * as v from 'valibot' import { AccountType } from '../enum/AccountType' import { InputTransactionType } from '../enum/InputTransactionType' import { @@ -35,7 +35,7 @@ const transactionLinkCode = (date: Date): string => { let topic: HieroId const topicString = '0.0.261' beforeAll(() => { - topic = parse(hieroIdSchema, topicString) + topic = v.parse(hieroIdSchema, topicString) }) describe('transaction schemas', () => { @@ -45,9 +45,9 @@ describe('transaction schemas', () => { let memo: Memo beforeAll(() => { userUuidString = uuidv4() - userUuid = parse(uuidv4Schema, userUuidString) + userUuid = v.parse(uuidv4Schema, userUuidString) memoString = 'TestMemo' - memo = parse(memoSchema, memoString) + memo = v.parse(memoSchema, memoString) }) describe('register address', () => { let registerAddress: TransactionInput @@ -63,7 +63,7 @@ describe('transaction schemas', () => { } }) it('valid transaction schema', () => { - expect(parse(transactionSchema, registerAddress)).toEqual({ + expect(v.parse(transactionSchema, registerAddress)).toEqual({ user: { communityTopicId: topic, account: { @@ -77,7 +77,7 @@ describe('transaction schemas', () => { }) }) it('valid register address schema', () => { - expect(parse(registerAddressTransactionSchema, registerAddress)).toEqual({ + expect(v.parse(registerAddressTransactionSchema, registerAddress)).toEqual({ user: { communityTopicId: topic, account: { @@ -112,7 +112,7 @@ describe('transaction schemas', () => { type: InputTransactionType.GRADIDO_TRANSFER, createdAt: '2022-01-01T00:00:00.000Z', } - expect(parse(transactionSchema, gradidoTransfer)).toEqual({ + expect(v.parse(transactionSchema, gradidoTransfer)).toEqual({ user: { communityTopicId: topic, account: { @@ -127,7 +127,7 @@ describe('transaction schemas', () => { accountNr: 0, }, }, - amount: parse(gradidoAmountSchema, gradidoTransfer.amount!), + amount: v.parse(gradidoAmountSchema, gradidoTransfer.amount!), memo, type: gradidoTransfer.type, createdAt: new Date(gradidoTransfer.createdAt), @@ -150,7 +150,7 @@ describe('transaction schemas', () => { createdAt: '2022-01-01T00:00:00.000Z', targetDate: '2021-11-01T10:00', } - expect(parse(transactionSchema, gradidoCreation)).toEqual({ + expect(v.parse(transactionSchema, gradidoCreation)).toEqual({ user: { communityTopicId: topic, account: { userUuid, accountNr: 0 }, @@ -159,7 +159,7 @@ describe('transaction schemas', () => { communityTopicId: topic, account: { userUuid, accountNr: 0 }, }, - amount: parse(gradidoAmountSchema, gradidoCreation.amount!), + amount: v.parse(gradidoAmountSchema, gradidoCreation.amount!), memo, type: gradidoCreation.type, createdAt: new Date(gradidoCreation.createdAt), @@ -168,7 +168,7 @@ describe('transaction schemas', () => { }) it('valid, gradido transaction link / deferred transfer', () => { const seed = transactionLinkCode(new Date()) - const seedParsed = parse(identifierSeedSchema, seed) + const seedParsed = v.parse(identifierSeedSchema, seed) const gradidoTransactionLink: TransactionInput = { user: { communityTopicId: topicString, @@ -186,7 +186,7 @@ describe('transaction schemas', () => { createdAt: '2022-01-01T00:00:00.000Z', timeoutDuration: 60 * 60 * 24 * 30, } - expect(parse(transactionSchema, gradidoTransactionLink)).toEqual({ + expect(v.parse(transactionSchema, gradidoTransactionLink)).toEqual({ user: { communityTopicId: topic, account: { @@ -198,11 +198,11 @@ describe('transaction schemas', () => { communityTopicId: topic, seed: seedParsed, }, - amount: parse(gradidoAmountSchema, gradidoTransactionLink.amount!), + amount: v.parse(gradidoAmountSchema, gradidoTransactionLink.amount!), memo, type: gradidoTransactionLink.type, createdAt: new Date(gradidoTransactionLink.createdAt), - timeoutDuration: parse(timeoutDurationSchema, gradidoTransactionLink.timeoutDuration!), + timeoutDuration: v.parse(timeoutDurationSchema, gradidoTransactionLink.timeoutDuration!), }) }) }) diff --git a/dlt-connector/src/server/index.test.ts b/dlt-connector/src/server/index.test.ts index 3fa0ce07b..9ec7f236a 100644 --- a/dlt-connector/src/server/index.test.ts +++ b/dlt-connector/src/server/index.test.ts @@ -1,8 +1,8 @@ import { beforeAll, describe, expect, it, mock } from 'bun:test' import { AccountId, Timestamp, TransactionId } from '@hashgraph/sdk' import { GradidoTransaction, KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' -import { parse } from 'valibot' -import { KeyPairCacheManager } from '../KeyPairCacheManager' +import * as v from 'valibot' +import { KeyPairCacheManager } from '../cache/KeyPairCacheManager' import { HieroId, hieroIdSchema } from '../schemas/typeGuard.schema' import { appRoutes } from '.' @@ -44,7 +44,7 @@ mock.module('../config', () => ({ })) beforeAll(() => { - KeyPairCacheManager.getInstance().setHomeCommunityTopicId(parse(hieroIdSchema, '0.0.21732')) + KeyPairCacheManager.getInstance().setHomeCommunityTopicId(v.parse(hieroIdSchema, '0.0.21732')) }) describe('Server', () => { From 1560486dd39fb44ca21741a8f95b28a401520d9e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 14:21:05 +0200 Subject: [PATCH 057/226] split main code --- dlt-connector/src/bootstrap/appContext.ts | 26 +++++ dlt-connector/src/bootstrap/init.ts | 81 +++++++++++++ dlt-connector/src/bootstrap/shutdown.ts | 28 +++++ dlt-connector/src/index.ts | 132 ++-------------------- 4 files changed, 147 insertions(+), 120 deletions(-) create mode 100644 dlt-connector/src/bootstrap/appContext.ts create mode 100644 dlt-connector/src/bootstrap/init.ts create mode 100644 dlt-connector/src/bootstrap/shutdown.ts diff --git a/dlt-connector/src/bootstrap/appContext.ts b/dlt-connector/src/bootstrap/appContext.ts new file mode 100644 index 000000000..5a1cbbc18 --- /dev/null +++ b/dlt-connector/src/bootstrap/appContext.ts @@ -0,0 +1,26 @@ +import { BackendClient } from '../client/backend/BackendClient' +import { HieroClient } from '../client/hiero/HieroClient' +import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' +import { KeyPairCacheManager } from '../cache/KeyPairCacheManager' + +export type AppContextClients = { + backend: BackendClient + hiero: HieroClient + gradidoNode: GradidoNodeClient +} + +export type AppContext = { + cache: KeyPairCacheManager + clients: AppContextClients +} + +export function createAppContext(): AppContext { + return { + cache: KeyPairCacheManager.getInstance(), + clients: { + backend: BackendClient.getInstance(), + hiero: HieroClient.getInstance(), + gradidoNode: GradidoNodeClient.getInstance(), + }, + } +} \ No newline at end of file diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts new file mode 100644 index 000000000..dfd0f7226 --- /dev/null +++ b/dlt-connector/src/bootstrap/init.ts @@ -0,0 +1,81 @@ +import { readFileSync } from 'node:fs' +import { CONFIG } from '../config' +import { configure, getLogger, Logger } from 'log4js' +import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' +import { type AppContext, type AppContextClients } from './appContext' +import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from '../config/const' +import * as v from 'valibot' +import { Community, communitySchema } from '../schemas/transaction.schema' +import { isPortOpenRetry } from '../utils/network' +import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' + +export function loadConfig(): Logger { + // configure log4js + // TODO: replace late by loader from config-schema + const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) + configure(options) + const logger = getLogger('dlt') + + // load crypto keys for gradido blockchain lib + loadCryptoKeys( + MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), + MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY), + ) + return logger +} + +export async function checkHieroAccount(logger: Logger, clients: AppContextClients): Promise { + const balance = await clients.hiero.getBalance() + logger.info(`Hiero Account Balance: ${balance.hbars.toString()}`) +} + +export async function checkHomeCommunity(appContext: AppContext, logger: Logger): Promise { + const { backend, hiero } = appContext.clients + + // wait for backend server + await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) + // ask backend for home community + let homeCommunity = await backend.getHomeCommunityDraft() + // on missing topicId, create one + if (!homeCommunity.hieroTopicId) { + const topicId = await hiero.createTopic(homeCommunity.name) + // update topic on backend server + homeCommunity = await backend.setHomeCommunityTopicId(homeCommunity.uuid, topicId) + } else { + // if topic exist, check if we need to update it + let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) + // console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`) + if ( + topicInfo.expirationTime.getTime() - new Date().getTime() < + MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE + ) { + await hiero.updateTopic(homeCommunity.hieroTopicId) + topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) + logger.info( + `updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`, + ) + } + } + if (!homeCommunity.hieroTopicId) { + throw new Error('still no topic id, after creating topic and update community in backend.') + } + appContext.cache.setHomeCommunityTopicId(homeCommunity.hieroTopicId) + logger.info(`home community topic: ${homeCommunity.hieroTopicId}`) + logger.info(`gradido node server: ${CONFIG.NODE_SERVER_URL}`) + logger.info(`gradido backend server: ${CONFIG.BACKEND_SERVER_URL}`) + return v.parse(communitySchema, homeCommunity) +} + +export async function checkGradidoNode(clients: AppContextClients, logger: Logger, homeCommunity: Community): Promise { + // ask gradido node if community blockchain was created + try { + if ( + !(await clients.gradidoNode.getTransaction({ transactionId: 1, topic: homeCommunity.hieroTopicId })) + ) { + // if not exist, create community root transaction + await SendToHieroContext(homeCommunity) + } + } catch (e) { + logger.error(`error requesting gradido node: ${e}`) + } +} \ No newline at end of file diff --git a/dlt-connector/src/bootstrap/shutdown.ts b/dlt-connector/src/bootstrap/shutdown.ts new file mode 100644 index 000000000..7c9b48c80 --- /dev/null +++ b/dlt-connector/src/bootstrap/shutdown.ts @@ -0,0 +1,28 @@ +import { Logger } from 'log4js' +import { type AppContextClients } from './appContext' + +export function setupGracefulShutdown(logger: Logger, clients: AppContextClients) { + const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'] + signals.forEach((sig) => { + process.on(sig, async () => { + logger.info(`[shutdown] Got ${sig}, cleaning up…`) + await gracefulShutdown(logger, clients) + process.exit(0) + }) + }) + + if (process.platform === 'win32') { + const rl = require('readline').createInterface({ + input: process.stdin, + output: process.stdout, + }) + rl.on('SIGINT', () => { + process.emit('SIGINT' as any) + }) + } +} + +async function gracefulShutdown(logger: Logger, clients: AppContextClients) { + logger.info('graceful shutdown') + await clients.hiero.waitForPendingPromises() +} \ No newline at end of file diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index 22ae267e2..eb82bab91 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,141 +1,33 @@ -import { readFileSync } from 'node:fs' import { Elysia } from 'elysia' -import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' -import { configure, getLogger, Logger } from 'log4js' -import * as v from 'valibot' -import { KeyPairCacheManager } from './cache/KeyPairCacheManager' -import { BackendClient } from './client/backend/BackendClient' -import { GradidoNodeClient } from './client/GradidoNode/GradidoNodeClient' -import { HieroClient } from './client/hiero/HieroClient' import { CONFIG } from './config' -import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from './config/const' -import { SendToHieroContext } from './interactions/sendToHiero/SendToHiero.context' -import { Community, communitySchema } from './schemas/transaction.schema' import { appRoutes } from './server' -import { isPortOpenRetry } from './utils/network' - -type Clients = { - backend: BackendClient - hiero: HieroClient - gradidoNode: GradidoNodeClient -} +import { setupGracefulShutdown } from './bootstrap/shutdown' +import { createAppContext } from './bootstrap/appContext' +import { checkHieroAccount, checkHomeCommunity, checkGradidoNode, loadConfig } from './bootstrap/init' async function main() { - // load everything from .env + // load log4js-config, logger and gradido-blockchain-js crypto keys const logger = loadConfig() - const clients = createClients() - const { hiero, gradidoNode } = clients + // initialize singletons (clients and cache) + const appContext = createAppContext() // show hiero account balance, double also as check if valid hiero account was given in config - const balance = await hiero.getBalance() - logger.info(`Hiero Account Balance: ${balance.hbars.toString()}`) + await checkHieroAccount(logger, appContext.clients) // get home community, create topic if not exist, or check topic expiration and update it if needed - const homeCommunity = await homeCommunitySetup(clients, logger) + const homeCommunity = await checkHomeCommunity(appContext, logger) // ask gradido node if community blockchain was created - try { - if ( - !(await gradidoNode.getTransaction({ transactionId: 1, topic: homeCommunity.hieroTopicId })) - ) { - // if not exist, create community root transaction - await SendToHieroContext(homeCommunity) - } - } catch (e) { - logger.error(`error requesting gradido node: ${e}`) - } + // if not exist, create community root transaction + await checkGradidoNode(appContext.clients, logger, homeCommunity) + // listen for rpc request from backend (graphql replaced with elysiaJS) new Elysia().use(appRoutes).listen(CONFIG.DLT_CONNECTOR_PORT, () => { logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) - setupGracefulShutdown(logger) + setupGracefulShutdown(logger, appContext.clients) }) } -function setupGracefulShutdown(logger: Logger) { - const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'] - signals.forEach((sig) => { - process.on(sig, async () => { - logger.info(`[shutdown] Got ${sig}, cleaning up…`) - await gracefulShutdown(logger) - process.exit(0) - }) - }) - - if (process.platform === 'win32') { - const rl = require('readline').createInterface({ - input: process.stdin, - output: process.stdout, - }) - rl.on('SIGINT', () => { - process.emit('SIGINT' as any) - }) - } -} - -async function gracefulShutdown(logger: Logger) { - logger.info('graceful shutdown') - await HieroClient.getInstance().waitForPendingPromises() -} - -function loadConfig(): Logger { - // configure log4js - // TODO: replace late by loader from config-schema - const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) - configure(options) - const logger = getLogger('dlt') - - // load crypto keys for gradido blockchain lib - loadCryptoKeys( - MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET), - MemoryBlock.fromHex(CONFIG.GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY), - ) - return logger -} - -// needed to be called after loading config -function createClients(): Clients { - return { - backend: BackendClient.getInstance(), - hiero: HieroClient.getInstance(), - gradidoNode: GradidoNodeClient.getInstance(), - } -} - -async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger): Promise { - // wait for backend server - await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) - // ask backend for home community - let homeCommunity = await backend.getHomeCommunityDraft() - // on missing topicId, create one - if (!homeCommunity.hieroTopicId) { - const topicId = await hiero.createTopic(homeCommunity.name) - // update topic on backend server - homeCommunity = await backend.setHomeCommunityTopicId(homeCommunity.uuid, topicId) - } else { - // if topic exist, check if we need to update it - let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) - // console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`) - if ( - topicInfo.expirationTime.getTime() - new Date().getTime() < - MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE - ) { - await hiero.updateTopic(homeCommunity.hieroTopicId) - topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId) - logger.info( - `updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`, - ) - } - } - if (!homeCommunity.hieroTopicId) { - throw new Error('still no topic id, after creating topic and update community in backend.') - } - KeyPairCacheManager.getInstance().setHomeCommunityTopicId(homeCommunity.hieroTopicId) - logger.info(`home community topic: ${homeCommunity.hieroTopicId}`) - logger.info(`gradido node server: ${CONFIG.NODE_SERVER_URL}`) - logger.info(`gradido backend server: ${CONFIG.BACKEND_SERVER_URL}`) - return v.parse(communitySchema, homeCommunity) -} - main().catch((e) => { // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) From 7ef816ea80157b1fa39c6da5c460b0390fa1cbf5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 14:22:12 +0200 Subject: [PATCH 058/226] fix lint --- dlt-connector/src/bootstrap/appContext.ts | 8 ++--- dlt-connector/src/bootstrap/init.ts | 44 ++++++++++++++--------- dlt-connector/src/bootstrap/shutdown.ts | 2 +- dlt-connector/src/index.ts | 13 ++++--- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/dlt-connector/src/bootstrap/appContext.ts b/dlt-connector/src/bootstrap/appContext.ts index 5a1cbbc18..44d69b619 100644 --- a/dlt-connector/src/bootstrap/appContext.ts +++ b/dlt-connector/src/bootstrap/appContext.ts @@ -1,7 +1,7 @@ -import { BackendClient } from '../client/backend/BackendClient' -import { HieroClient } from '../client/hiero/HieroClient' -import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' import { KeyPairCacheManager } from '../cache/KeyPairCacheManager' +import { BackendClient } from '../client/backend/BackendClient' +import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' +import { HieroClient } from '../client/hiero/HieroClient' export type AppContextClients = { backend: BackendClient @@ -23,4 +23,4 @@ export function createAppContext(): AppContext { gradidoNode: GradidoNodeClient.getInstance(), }, } -} \ No newline at end of file +} diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index dfd0f7226..1d70f4003 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -1,13 +1,13 @@ import { readFileSync } from 'node:fs' -import { CONFIG } from '../config' -import { configure, getLogger, Logger } from 'log4js' import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' -import { type AppContext, type AppContextClients } from './appContext' -import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from '../config/const' +import { configure, getLogger, Logger } from 'log4js' import * as v from 'valibot' +import { CONFIG } from '../config' +import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE } from '../config/const' +import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' import { Community, communitySchema } from '../schemas/transaction.schema' import { isPortOpenRetry } from '../utils/network' -import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.context' +import { type AppContext, type AppContextClients } from './appContext' export function loadConfig(): Logger { // configure log4js @@ -29,7 +29,10 @@ export async function checkHieroAccount(logger: Logger, clients: AppContextClien logger.info(`Hiero Account Balance: ${balance.hbars.toString()}`) } -export async function checkHomeCommunity(appContext: AppContext, logger: Logger): Promise { +export async function checkHomeCommunity( + appContext: AppContext, + logger: Logger, +): Promise { const { backend, hiero } = appContext.clients // wait for backend server @@ -66,16 +69,23 @@ export async function checkHomeCommunity(appContext: AppContext, logger: Logger) return v.parse(communitySchema, homeCommunity) } -export async function checkGradidoNode(clients: AppContextClients, logger: Logger, homeCommunity: Community): Promise { +export async function checkGradidoNode( + clients: AppContextClients, + logger: Logger, + homeCommunity: Community, +): Promise { // ask gradido node if community blockchain was created - try { - if ( - !(await clients.gradidoNode.getTransaction({ transactionId: 1, topic: homeCommunity.hieroTopicId })) - ) { - // if not exist, create community root transaction - await SendToHieroContext(homeCommunity) - } - } catch (e) { - logger.error(`error requesting gradido node: ${e}`) + try { + if ( + !(await clients.gradidoNode.getTransaction({ + transactionId: 1, + topic: homeCommunity.hieroTopicId, + })) + ) { + // if not exist, create community root transaction + await SendToHieroContext(homeCommunity) } -} \ No newline at end of file + } catch (e) { + logger.error(`error requesting gradido node: ${e}`) + } +} diff --git a/dlt-connector/src/bootstrap/shutdown.ts b/dlt-connector/src/bootstrap/shutdown.ts index 7c9b48c80..781430008 100644 --- a/dlt-connector/src/bootstrap/shutdown.ts +++ b/dlt-connector/src/bootstrap/shutdown.ts @@ -25,4 +25,4 @@ export function setupGracefulShutdown(logger: Logger, clients: AppContextClients async function gracefulShutdown(logger: Logger, clients: AppContextClients) { logger.info('graceful shutdown') await clients.hiero.waitForPendingPromises() -} \ No newline at end of file +} diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index eb82bab91..1d4513e83 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -1,9 +1,14 @@ import { Elysia } from 'elysia' +import { createAppContext } from './bootstrap/appContext' +import { + checkGradidoNode, + checkHieroAccount, + checkHomeCommunity, + loadConfig, +} from './bootstrap/init' +import { setupGracefulShutdown } from './bootstrap/shutdown' import { CONFIG } from './config' import { appRoutes } from './server' -import { setupGracefulShutdown } from './bootstrap/shutdown' -import { createAppContext } from './bootstrap/appContext' -import { checkHieroAccount, checkHomeCommunity, checkGradidoNode, loadConfig } from './bootstrap/init' async function main() { // load log4js-config, logger and gradido-blockchain-js crypto keys @@ -20,7 +25,7 @@ async function main() { // ask gradido node if community blockchain was created // if not exist, create community root transaction await checkGradidoNode(appContext.clients, logger, homeCommunity) - + // listen for rpc request from backend (graphql replaced with elysiaJS) new Elysia().use(appRoutes).listen(CONFIG.DLT_CONNECTOR_PORT, () => { logger.info(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`) From b3eea7ab471232c658a4b5cc63292b5f06942d0a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 14:51:22 +0200 Subject: [PATCH 059/226] move files around, rename them --- .../src/client/GradidoNode/GradidoNodeClient.ts | 4 ++-- .../GradidoNode}/GradidoNodeErrorCodes.ts | 0 .../AccountType.ts => data/AccountType.enum.ts} | 0 .../AddressType.ts => data/AddressType.enum.ts} | 0 .../InputTransactionType.enum.ts} | 0 dlt-connector/src/enum/TransactionErrorType.ts | 15 --------------- .../sendToHiero/SendToHiero.context.ts | 2 +- .../src/schemas/transaction.schema.test.ts | 4 ++-- dlt-connector/src/schemas/transaction.schema.ts | 4 ++-- .../src/schemas/typeConverter.schema.test.ts | 2 +- dlt-connector/src/schemas/typeConverter.schema.ts | 4 ++-- dlt-connector/src/utils/typeConverter.ts | 4 ++-- 12 files changed, 12 insertions(+), 27 deletions(-) rename dlt-connector/src/{enum => client/GradidoNode}/GradidoNodeErrorCodes.ts (100%) rename dlt-connector/src/{enum/AccountType.ts => data/AccountType.enum.ts} (100%) rename dlt-connector/src/{enum/AddressType.ts => data/AddressType.enum.ts} (100%) rename dlt-connector/src/{enum/InputTransactionType.ts => data/InputTransactionType.enum.ts} (100%) delete mode 100644 dlt-connector/src/enum/TransactionErrorType.ts diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index 9f43b95ef..efbfc6d22 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -5,12 +5,12 @@ import { getLogger, Logger } from 'log4js' import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { AddressType } from '../../data/AddressType.enum' import { Uuidv4Hash } from '../../data/Uuidv4Hash' -import { AddressType } from '../../enum/AddressType' -import { GradidoNodeErrorCodes } from '../../enum/GradidoNodeErrorCodes' import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' import { Hex32, Hex32Input, HieroId, hex32Schema } from '../../schemas/typeGuard.schema' import { isPortOpenRetry } from '../../utils/network' +import { GradidoNodeErrorCodes } from './GradidoNodeErrorCodes' import { TransactionIdentifierInput, TransactionsRangeInput, diff --git a/dlt-connector/src/enum/GradidoNodeErrorCodes.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeErrorCodes.ts similarity index 100% rename from dlt-connector/src/enum/GradidoNodeErrorCodes.ts rename to dlt-connector/src/client/GradidoNode/GradidoNodeErrorCodes.ts diff --git a/dlt-connector/src/enum/AccountType.ts b/dlt-connector/src/data/AccountType.enum.ts similarity index 100% rename from dlt-connector/src/enum/AccountType.ts rename to dlt-connector/src/data/AccountType.enum.ts diff --git a/dlt-connector/src/enum/AddressType.ts b/dlt-connector/src/data/AddressType.enum.ts similarity index 100% rename from dlt-connector/src/enum/AddressType.ts rename to dlt-connector/src/data/AddressType.enum.ts diff --git a/dlt-connector/src/enum/InputTransactionType.ts b/dlt-connector/src/data/InputTransactionType.enum.ts similarity index 100% rename from dlt-connector/src/enum/InputTransactionType.ts rename to dlt-connector/src/data/InputTransactionType.enum.ts diff --git a/dlt-connector/src/enum/TransactionErrorType.ts b/dlt-connector/src/enum/TransactionErrorType.ts deleted file mode 100644 index 0da6ebb53..000000000 --- a/dlt-connector/src/enum/TransactionErrorType.ts +++ /dev/null @@ -1,15 +0,0 @@ -// enum for graphql -// error groups for resolver answers -export enum TransactionErrorType { - NOT_IMPLEMENTED_YET = 'Not Implemented yet', - MISSING_PARAMETER = 'Missing parameter', - INVALID_PARAMETER = 'Invalid parameter', - ALREADY_EXIST = 'Already exist', - DB_ERROR = 'DB Error', - PROTO_DECODE_ERROR = 'Proto Decode Error', - PROTO_ENCODE_ERROR = 'Proto Encode Error', - INVALID_SIGNATURE = 'Invalid Signature', - LOGIC_ERROR = 'Logic Error', - NOT_FOUND = 'Not found', - VALIDATION_ERROR = 'Validation Error', -} diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index e3ab0b7ed..1dd74976c 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -9,7 +9,7 @@ import { getLogger } from 'log4js' import * as v from 'valibot' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { InputTransactionType } from '../../enum/InputTransactionType' +import { InputTransactionType } from '../../data/InputTransactionType.enum' import { CommunityInput, communitySchema, diff --git a/dlt-connector/src/schemas/transaction.schema.test.ts b/dlt-connector/src/schemas/transaction.schema.test.ts index 533cd35b9..de22e98ba 100644 --- a/dlt-connector/src/schemas/transaction.schema.test.ts +++ b/dlt-connector/src/schemas/transaction.schema.test.ts @@ -5,8 +5,8 @@ import { randomBytes } from 'crypto' import { AddressType_COMMUNITY_HUMAN } from 'gradido-blockchain-js' import { v4 as uuidv4 } from 'uuid' import * as v from 'valibot' -import { AccountType } from '../enum/AccountType' -import { InputTransactionType } from '../enum/InputTransactionType' +import { AccountType } from '../data/AccountType.enum' +import { InputTransactionType } from '../data/InputTransactionType.enum' import { gradidoAmountSchema, HieroId, diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index dea8c48dc..b018a8e86 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -1,6 +1,6 @@ import * as v from 'valibot' -import { AccountType } from '../enum/AccountType' -import { InputTransactionType } from '../enum/InputTransactionType' +import { AccountType } from '../data/AccountType.enum' +import { InputTransactionType } from '../data/InputTransactionType.enum' import { identifierAccountSchema, identifierCommunityAccountSchema } from './account.schema' import { addressTypeSchema, dateSchema } from './typeConverter.schema' import { diff --git a/dlt-connector/src/schemas/typeConverter.schema.test.ts b/dlt-connector/src/schemas/typeConverter.schema.test.ts index 2caa499b5..5420de106 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.test.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.test.ts @@ -4,7 +4,7 @@ import { TypeCompiler } from '@sinclair/typebox/compiler' import { Static, TypeBoxFromValibot } from '@sinclair/typemap' import { AddressType_COMMUNITY_AUF } from 'gradido-blockchain-js' import * as v from 'valibot' -import { AccountType } from '../enum/AccountType' +import { AccountType } from '../data/AccountType.enum' import { accountTypeSchema, addressTypeSchema, diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 2e4811c11..3d68cfe24 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -1,7 +1,7 @@ import { ConfirmedTransaction } from 'gradido-blockchain-js' import * as v from 'valibot' -import { AccountType } from '../enum/AccountType' -import { AddressType } from '../enum/AddressType' +import { AccountType } from '../data/AccountType.enum' +import { AddressType } from '../data/AddressType.enum' import { confirmedTransactionFromBase64, isAddressType, diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 5b1279beb..148efebd6 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -4,8 +4,8 @@ import { InteractionDeserialize, MemoryBlock, } from 'gradido-blockchain-js' -import { AccountType } from '../enum/AccountType' -import { AddressType } from '../enum/AddressType' +import { AccountType } from '../data/AccountType.enum' +import { AddressType } from '../data/AddressType.enum' export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64)) From 3bdb5427950bd0f7ff004226c8ec2b28486c7ddf Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 22 Oct 2025 15:13:03 +0200 Subject: [PATCH 060/226] move output schema from server in correct file --- dlt-connector/src/server/index.ts | 2 +- dlt-connector/src/server/input.schema.ts | 4 ---- dlt-connector/src/server/output.schema.ts | 5 +++++ 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 dlt-connector/src/server/output.schema.ts diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 7168a76dc..406d04d06 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -14,8 +14,8 @@ import { hieroTransactionIdStringSchema } from '../schemas/typeGuard.schema' import { accountIdentifierSeedTypeBoxSchema, accountIdentifierUserTypeBoxSchema, - existTypeBoxSchema, } from './input.schema' +import { existTypeBoxSchema } from './output.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) diff --git a/dlt-connector/src/server/input.schema.ts b/dlt-connector/src/server/input.schema.ts index 515e5b35f..df93f1d9b 100644 --- a/dlt-connector/src/server/input.schema.ts +++ b/dlt-connector/src/server/input.schema.ts @@ -13,7 +13,3 @@ export const accountIdentifierSeedTypeBoxSchema = t.Object({ communityTopicId: TypeBoxFromValibot(hieroIdSchema), seed: TypeBoxFromValibot(uuidv4Schema), }) - -export const existTypeBoxSchema = t.Object({ - exists: t.Boolean(), -}) diff --git a/dlt-connector/src/server/output.schema.ts b/dlt-connector/src/server/output.schema.ts new file mode 100644 index 000000000..845871317 --- /dev/null +++ b/dlt-connector/src/server/output.schema.ts @@ -0,0 +1,5 @@ +import { t } from 'elysia' + +export const existTypeBoxSchema = t.Object({ + exists: t.Boolean(), +}) From 190ba6d67831e94f6988ec7f70f9bf2d4d929fb1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 23 Oct 2025 08:10:12 +0200 Subject: [PATCH 061/226] copy pr message into readme --- dlt-connector/README.md | 63 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/dlt-connector/README.md b/dlt-connector/README.md index d56e77437..8c7722092 100644 --- a/dlt-connector/README.md +++ b/dlt-connector/README.md @@ -1 +1,62 @@ -# Elysia with Bun runtime +# DLT Connector + +## Overview + +This implements the **DLT Connector** using [gradido-blockchain-js](https://github.com/gradido/gradido-blockchain-js) as a Node module. +[gradido-blockchain-js](https://github.com/gradido/gradido-blockchain-js) builds the native library [gradido_blockchain](https://github.com/gradido/gradido_blockchain) via SWIG, making it accessible to Node.js. + +Most of the Logic is handled by gradido-blockchain. +The connector’s purpose is to send Gradido transactions, serialized in blockchain format, through the Hiero SDK into the Hedera Network as Topic Messages. +The [gradido-node](https://github.com/gradido/gradido_node) listens to these Hedera/Hiero topics, validates the transactions, and stores them efficiently. +Transactions can then be retrieved via a JSON-RPC 2.0 API from [gradido-node](https://github.com/gradido/gradido_node) + +--- + +## Structure + +The module makes extensive use of schema validation with [Valibot](https://valibot.dev/guides/introduction/). +All objects without internal logic are represented as Valibot schemas, with their corresponding TypeScript types inferred automatically. +Valibot allows clear separation of *input* and *output* types, reducing the need for repetitive `null | undefined` checks. +When a function expects an output type, TypeScript ensures that the data has been validated via `parse` or `safeParse`, guaranteeing type safety at runtime. + +--- + +### `src/bootstrap` +Contains initialization code executed once at program startup by `src/index.ts`. + +### `src/cache` +Contains code for caching expensive computations or remote data. +Currently used only by `KeyPairCacheManager`. + +### `src/client` +Contains the client implementations for communication with +[`gradido-node`](https://github.com/gradido/gradido_node), the backend, and the Hiero service. +Each `Client` class is a singleton providing: +- configuration and connection management +- API-call methods mirroring the target service +Each client may include optional `input.schema.ts` and/or `output.schema.ts` files defining Valibot schemas for its complex data structures. + +### `src/config` +Contains the Valibot-based configuration schema, default values, and logic for parsing `process.env`. +If a required field is missing or invalid, the module prints an error and terminates the process. + +### `src/data` +Contains DCI (Data-Context-Interaction) Data Objects: +simple domain objects that are difficult to express as Valibot schemas, as well as Logic Objects containing core business logic. +Also includes domain enums. + +### `src/interactions` +Contains complex business logic (Interactions in DCI terms). +Each use case resides in its own subfolder with one Context Object and corresponding Role Objects. + +### `src/schemas` +Contains Valibot schemas shared across multiple parts of the program. + +### `src/server` +Contains the [Elysia](https://elysiajs.com/at-glance.html)-based REST API used by the backend to submit new Gradido transactions. +It is intended to integrate with Valibot schemas; currently, it uses `@sinclair/typebox` to convert Valibot schemas to the native format expected by Elysia. + +### `src/utils` +Contains small, generic helper functions that do not clearly fit into any of the other directories. + +--- From e2cda2c297d60fd12b26322bd6c85088962596f9 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 23 Oct 2025 09:53:34 +0200 Subject: [PATCH 062/226] update constructing of backend and gradido node server urls --- dlt-connector/.env.dist | 4 ++-- dlt-connector/src/bootstrap/init.ts | 6 ++--- .../client/GradidoNode/GradidoNodeClient.ts | 12 ++++++++-- dlt-connector/src/config/schema.ts | 22 ++++++++++++++----- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index ff40bd5d1..8253699ca 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -13,12 +13,12 @@ IOTA_HOME_COMMUNITY_SEED=aabbccddeeff00112233445566778899aabbccddeeff00112233445 DLT_CONNECTOR_PORT=6010 # Gradido Node Server URL -NODE_SERVER_URL=http://localhost:8340/api +DLT_NODE_SERVER_PORT=8340 # Gradido Blockchain GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=21ffbbc616fe GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=a51ef8ac7ef1abf162fb7a65261acd7a # Route to Backend -BACKEND_SERVER_URL=http://localhost:4000 +PORT=4000 JWT_SECRET=secret123 \ No newline at end of file diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index 1d70f4003..c41553594 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -36,7 +36,7 @@ export async function checkHomeCommunity( const { backend, hiero } = appContext.clients // wait for backend server - await isPortOpenRetry(CONFIG.BACKEND_SERVER_URL) + await isPortOpenRetry(backend.url) // ask backend for home community let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one @@ -64,8 +64,8 @@ export async function checkHomeCommunity( } appContext.cache.setHomeCommunityTopicId(homeCommunity.hieroTopicId) logger.info(`home community topic: ${homeCommunity.hieroTopicId}`) - logger.info(`gradido node server: ${CONFIG.NODE_SERVER_URL}`) - logger.info(`gradido backend server: ${CONFIG.BACKEND_SERVER_URL}`) + logger.info(`gradido node server: ${appContext.clients.gradidoNode.url}`) + logger.info(`gradido backend server: ${appContext.clients.backend.url}`) return v.parse(communitySchema, homeCommunity) } diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index efbfc6d22..3bd3bab51 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -36,13 +36,21 @@ export class GradidoNodeClient { private static instance: GradidoNodeClient client: JsonRpcClient logger: Logger + urlValue: string private constructor() { this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNodeClient`) + this.urlValue = `http://localhost:${CONFIG.DLT_NODE_SERVER_PORT}` + this.logger.addContext('url', this.urlValue) this.client = new JsonRpcClient({ - url: CONFIG.NODE_SERVER_URL, + url: this.urlValue, }) } + + public get url(): string { + return this.urlValue + } + public static getInstance(): GradidoNodeClient { if (!GradidoNodeClient.instance) { GradidoNodeClient.instance = new GradidoNodeClient() @@ -233,7 +241,7 @@ export class GradidoNodeClient { // template rpcCall, check first if port is open before executing json rpc 2.0 request protected async rpcCall(method: string, parameter: any): Promise> { this.logger.debug('call %s with %s', method, parameter) - await isPortOpenRetry(CONFIG.NODE_SERVER_URL) + await isPortOpenRetry(this.url) return this.client.exec(method, parameter) } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 08eeb2b80..2ce01dcee 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -69,12 +69,22 @@ export const configSchema = v.object({ ), 500, ), - NODE_SERVER_URL: v.optional( - v.string('The URL of the gradido node server'), - 'http://localhost:6010', + DLT_NODE_SERVER_PORT: v.optional( + v.pipe( + v.string('A valid port on which the DLT node server is running'), + v.transform((input: string) => Number(input)), + v.minValue(1), + v.maxValue(65535), + ), + '8340', ), - BACKEND_SERVER_URL: v.optional( - v.string('The URL of the gradido backend server'), - 'http://localhost:6010', + PORT: v.optional( + v.pipe( + v.string('A valid port on which the backend server is running'), + v.transform((input: string) => Number(input)), + v.minValue(1), + v.maxValue(65535), + ), + '4000', ), }) From 4b59cf2377a63840a6dba35610600138dc306bcb Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 24 Oct 2025 07:20:49 +0200 Subject: [PATCH 063/226] add missing change --- dlt-connector/src/client/backend/BackendClient.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index d5cc3be9e..cee82769a 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -18,6 +18,7 @@ export class BackendClient { private static instance: BackendClient client: GraphQLClient logger: Logger + urlValue: string /** * The Singleton's constructor should always be private to prevent direct @@ -25,8 +26,10 @@ export class BackendClient { */ private constructor() { this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.BackendClient`) - this.logger.addContext('url', CONFIG.BACKEND_SERVER_URL) - this.client = new GraphQLClient(CONFIG.BACKEND_SERVER_URL, { + this.urlValue = `http://localhost:${CONFIG.PORT}` + this.logger.addContext('url', this.urlValue) + + this.client = new GraphQLClient(this.urlValue, { headers: { 'content-type': 'application/json', }, @@ -38,6 +41,10 @@ export class BackendClient { }) } + public get url(): string { + return this.url + } + /** * The static method that controls the access to the singleton instance. * From 567fbbaf66eae1bff00f2d884229884e7564e6fa Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 24 Oct 2025 07:49:06 +0200 Subject: [PATCH 064/226] check for valid recipient community topic before sending outbound cross group transaction --- dlt-connector/src/config/const.ts | 2 ++ .../sendToHiero/SendToHiero.context.ts | 6 +++++- dlt-connector/src/utils/hiero.ts | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 dlt-connector/src/utils/hiero.ts diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index e0dfc82a3..fa66eb6e7 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -1,3 +1,5 @@ export const LOG4JS_BASE_CATEGORY = 'dlt' // 7 days export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 +// 10 minutes +export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE = 1000 * 60 * 10 \ No newline at end of file diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 1dd74976c..f510be3bd 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -28,7 +28,7 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' - +import { isTopicStillOpen } from '../../utils/hiero' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) /** @@ -46,6 +46,10 @@ export async function SendToHieroContext( const outboundTransaction = builder.buildOutbound() validate(outboundTransaction) + if (!isTopicStillOpen(role.getRecipientCommunityTopicId())) { + throw new Error('recipient topic is not open long enough for sending messages') + } + // send outbound transaction to hiero at first, because we need the transaction id for inbound transaction const outboundHieroTransactionIdString = await sendViaHiero( outboundTransaction, diff --git a/dlt-connector/src/utils/hiero.ts b/dlt-connector/src/utils/hiero.ts new file mode 100644 index 000000000..9ea62042f --- /dev/null +++ b/dlt-connector/src/utils/hiero.ts @@ -0,0 +1,16 @@ +import { HieroId } from '../schemas/typeGuard.schema' +import { HieroClient } from '../client/hiero/HieroClient' +import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE } from '../config/const' + +/** + * Checks whether the given topic in the Hedera network will remain open + * for sending messages for at least `MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE` milliseconds. + * + * @param {HieroId} hieroTopicId - The topic ID to check. + * @returns {Promise} `true` if the topic is still open long enough, otherwise `false`. + */ +export async function isTopicStillOpen(hieroTopicId: HieroId): Promise { + const hieroClient = HieroClient.getInstance() + const topicInfo = await hieroClient.getTopicInfo(hieroTopicId) + return topicInfo.expirationTime.getTime() > new Date().getTime() + MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE +} \ No newline at end of file From 8983bc52ebf72f9a2cbf7363e770c5e68eced729 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 24 Oct 2025 08:28:53 +0200 Subject: [PATCH 065/226] add config option, if dlt-connector is enabled, write communities list for dlt gradido node server out in its home folder as communities.json on each validate communities run --- backend/src/config/index.ts | 1 + backend/src/config/schema.ts | 4 ++ .../client/1_0/model/PublicCommunityInfo.ts | 1 + backend/src/federation/validateCommunities.ts | 52 +++++++++++++++++++ deployment/bare_metal/.env.dist | 1 + .../1_0/model/GetPublicCommunityInfoResult.ts | 4 ++ 6 files changed, 63 insertions(+) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index aa0a7dbf2..b583156b5 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -43,6 +43,7 @@ const DLT_CONNECTOR_PORT = process.env.DLT_CONNECTOR_PORT ?? 6010 const dltConnector = { DLT_CONNECTOR: process.env.DLT_CONNECTOR === 'true' || false, DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `${COMMUNITY_URL}:${DLT_CONNECTOR_PORT}`, + DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: process.env.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER ?? '~/.gradido', } const community = { diff --git a/backend/src/config/schema.ts b/backend/src/config/schema.ts index 144608992..f4e6033ea 100644 --- a/backend/src/config/schema.ts +++ b/backend/src/config/schema.ts @@ -79,6 +79,10 @@ export const schema = Joi.object({ .when('DLT_CONNECTOR', { is: true, then: Joi.required() }) .description('The URL for GDT API endpoint'), + DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: Joi.string() + .default('~/.gradido') + .description('The home folder for the gradido dlt node server'), + EMAIL: Joi.boolean() .default(false) .description('Enable or disable email functionality') diff --git a/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts b/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts index 1abbeb9e7..7c228c799 100644 --- a/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts +++ b/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts @@ -4,4 +4,5 @@ export interface PublicCommunityInfo { creationDate: Date publicKey: string publicJwtKey: string + hieroTopicId: string | null } diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 10088cf35..3b910b313 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -2,6 +2,7 @@ import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity, getHomeCommunity, + getReachableCommunities, } from 'database' import { IsNull } from 'typeorm' @@ -15,6 +16,9 @@ import { getLogger } from 'log4js' import { startCommunityAuthentication } from './authenticateCommunities' import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view' import { ApiVersionType } from 'core' +import { CONFIG } from '@/config' +import * as path from 'node:path' +import * as fs from 'node:fs' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.validateCommunities`) @@ -83,6 +87,8 @@ export async function validateCommunities(): Promise { logger.error(`Error:`, err) } } + // export communities for gradido dlt node server + await exportCommunitiesToDltNodeServer() } export async function writeJwtKeyPairInHomeCommunity(): Promise { @@ -138,6 +144,52 @@ async function writeForeignCommunity( com.publicKey = dbCom.publicKey com.publicJwtKey = pubInfo.publicJwtKey com.url = dbCom.endPoint + com.hieroTopicId = pubInfo.hieroTopicId await DbCommunity.save(com) } } + +// prototype, later add api call to gradido dlt node server for adding/updating communities +type CommunityForDltNodeServer = { + communityId: string + hieroTopicId: string + alias: string + folder: string +} +async function exportCommunitiesToDltNodeServer(): Promise { + if (!CONFIG.DLT_CONNECTOR) { + return Promise.resolve() + } + const folder = CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER + try { + fs.accessSync(folder, fs.constants.R_OK | fs.constants.W_OK) + } catch (err) { + logger.error(`Error: home folder for DLT Gradido Node Server ${folder} does not exist`) + return + } + + const dbComs = await getReachableCommunities(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER * 4) + const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] + // make sure communityName is unique + const communityName = new Set() + dbComs.forEach((com) => { + if (!com.communityUuid || !com.hieroTopicId) { + return + } + let alias = com.name + if (!alias || communityName.has(alias)) { + alias = com.communityUuid + } + communityName.add(alias) + communitiesForDltNodeServer.push({ + communityId: com.communityUuid, + hieroTopicId: com.hieroTopicId, + alias, + // use only alpha-numeric chars for folder name + folder: alias.replace(/[^a-zA-Z0-9]/g, '_') + }) + }) + const dltNodeServerCommunitiesFile = path.join(folder, 'communities.json') + fs.writeFileSync(dltNodeServerCommunitiesFile, JSON.stringify(communitiesForDltNodeServer, null, 2)) + logger.debug(`Written communitiesForDltNodeServer to ${dltNodeServerCommunitiesFile}`) +} diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 11f5e1d76..729fc84aa 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -88,6 +88,7 @@ GDT_ACTIVE=false # DLT-Connector (still in develop) DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 +DLT_GRADIDO_NODE_SERVER_HOME_FOLDER=/home/gradido/.gradido # used for combining a newsletter on klicktipp with this gradido community # if used, user will be subscribed on register and can unsubscribe in his account diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index 55292cee2..1c7c5587c 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -12,6 +12,7 @@ export class GetPublicCommunityInfoResult { this.name = dbCom.name this.description = dbCom.description this.creationDate = dbCom.creationDate + this.hieroTopicId = dbCom.hieroTopicId } @Field(() => String) @@ -28,4 +29,7 @@ export class GetPublicCommunityInfoResult { @Field(() => String) publicJwtKey: string + + @Field(() => String) + hieroTopicId: string | null } From b9d51269ca062cd55cf7b3d68d6d7dedd965fa84 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 24 Oct 2025 08:36:07 +0200 Subject: [PATCH 066/226] fix lint --- dlt-connector/src/config/const.ts | 2 +- .../interactions/sendToHiero/SendToHiero.context.ts | 3 ++- dlt-connector/src/utils/hiero.ts | 11 +++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index fa66eb6e7..6b2a3b1a2 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -2,4 +2,4 @@ export const LOG4JS_BASE_CATEGORY = 'dlt' // 7 days export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 // 10 minutes -export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE = 1000 * 60 * 10 \ No newline at end of file +export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE = 1000 * 60 * 10 diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index f510be3bd..14427cacf 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -21,6 +21,7 @@ import { HieroTransactionIdString, hieroTransactionIdStringSchema, } from '../../schemas/typeGuard.schema' +import { isTopicStillOpen } from '../../utils/hiero' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' @@ -28,7 +29,7 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' -import { isTopicStillOpen } from '../../utils/hiero' + const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) /** diff --git a/dlt-connector/src/utils/hiero.ts b/dlt-connector/src/utils/hiero.ts index 9ea62042f..bd1501e83 100644 --- a/dlt-connector/src/utils/hiero.ts +++ b/dlt-connector/src/utils/hiero.ts @@ -1,9 +1,9 @@ -import { HieroId } from '../schemas/typeGuard.schema' import { HieroClient } from '../client/hiero/HieroClient' import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE } from '../config/const' +import { HieroId } from '../schemas/typeGuard.schema' /** - * Checks whether the given topic in the Hedera network will remain open + * Checks whether the given topic in the Hedera network will remain open * for sending messages for at least `MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE` milliseconds. * * @param {HieroId} hieroTopicId - The topic ID to check. @@ -12,5 +12,8 @@ import { MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE } from '../config/const' export async function isTopicStillOpen(hieroTopicId: HieroId): Promise { const hieroClient = HieroClient.getInstance() const topicInfo = await hieroClient.getTopicInfo(hieroTopicId) - return topicInfo.expirationTime.getTime() > new Date().getTime() + MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE -} \ No newline at end of file + return ( + topicInfo.expirationTime.getTime() > + new Date().getTime() + MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE + ) +} From f962baf1a1be6663200c6b1f2c2ca44acbd7678a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 24 Oct 2025 12:57:16 +0200 Subject: [PATCH 067/226] add process handler for starting and managing GradidoNode as subprocess --- dlt-connector/src/bootstrap/shutdown.ts | 2 + .../client/GradidoNode/GradidoNodeProcess.ts | 117 ++++++++++++++++++ dlt-connector/src/config/const.ts | 7 ++ dlt-connector/src/config/schema.ts | 1 + 4 files changed, 127 insertions(+) create mode 100644 dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts diff --git a/dlt-connector/src/bootstrap/shutdown.ts b/dlt-connector/src/bootstrap/shutdown.ts index 781430008..415742d38 100644 --- a/dlt-connector/src/bootstrap/shutdown.ts +++ b/dlt-connector/src/bootstrap/shutdown.ts @@ -1,4 +1,5 @@ import { Logger } from 'log4js' +import { GradidoNodeProcess } from '../client/GradidoNode/GradidoNodeProcess' import { type AppContextClients } from './appContext' export function setupGracefulShutdown(logger: Logger, clients: AppContextClients) { @@ -25,4 +26,5 @@ export function setupGracefulShutdown(logger: Logger, clients: AppContextClients async function gracefulShutdown(logger: Logger, clients: AppContextClients) { logger.info('graceful shutdown') await clients.hiero.waitForPendingPromises() + await GradidoNodeProcess.getInstance().exit() } diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts new file mode 100644 index 000000000..ad25c2461 --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -0,0 +1,117 @@ +import { Subprocess, spawn } from 'bun' +import { getLogger, Logger } from 'log4js' +import { CONFIG } from '../../config' +import { + GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS, + GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS, + GRADIDO_NODE_RUNTIME_PATH, + LOG4JS_BASE_CATEGORY, +} from '../../config/const' + +/** + * A Singleton class defines the `getInstance` method that lets clients access + * the unique singleton instance. + * + * Singleton Managing GradidoNode if started as subprocess + * will restart GradidoNode if it exits more than `GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS` milliseconds after start + * if exit was called, it will first try to exit graceful with SIGTERM and then kill with SIGKILL after `GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS` milliseconds + */ +export class GradidoNodeProcess { + private static instance: GradidoNodeProcess | null = null + private proc: Subprocess | null = null + private logger: Logger + private lastStarted: Date | null = null + private exitCalled: boolean = false + + private constructor() { + // constructor is private to prevent instantiation from outside + // of the class except from the static getInstance method. + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNodeProcess`) + } + + /** + * Static method that returns the singleton instance of the class. + * @returns the singleton instance of the class. + */ + public static getInstance(): GradidoNodeProcess { + if (!GradidoNodeProcess.instance) { + GradidoNodeProcess.instance = new GradidoNodeProcess() + } + return GradidoNodeProcess.instance + } + + public start() { + if (this.proc) { + this.logger.warn('GradidoNodeProcess already running.') + return + } + this.logger.info(`starting GradidoNodeProcess with path: ${GRADIDO_NODE_RUNTIME_PATH}`) + this.lastStarted = new Date() + const logger = this.logger + this.proc = spawn([GRADIDO_NODE_RUNTIME_PATH], { + env: { + CLIENTS_HIERO_NETWORKTYPE: CONFIG.HIERO_HEDERA_NETWORK, + SERVER_JSON_RPC_PORT: CONFIG.DLT_NODE_SERVER_PORT.toString(), + }, + onExit(proc, exitCode, signalCode, error) { + logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`) + if (error) { + logger.error(`GradidoNodeProcess exit error: ${error}`) + if (logger.isDebugEnabled() && proc.stderr) { + // print error messages from GradidoNode in our own log if debug is enabled + proc.stderr + .getReader() + .read() + .then((chunk) => { + logger.debug(chunk.value?.toString()) + }) + } + } + logger.debug(`ressource usage: ${proc?.resourceUsage()}`) + const gradidoNodeProcess = GradidoNodeProcess.getInstance() + gradidoNodeProcess.proc = null + if ( + !gradidoNodeProcess.exitCalled && + gradidoNodeProcess.lastStarted && + Date.now() - gradidoNodeProcess.lastStarted.getTime() > + GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS + ) { + // restart only if enough time was passed since last start to prevent restart loop + gradidoNodeProcess.start() + } + }, + stdout: 'ignore', + stderr: logger.isDebugEnabled() ? 'pipe' : 'ignore', + }) + } + + public async restart() { + if (this.proc) { + await this.exit() + this.exitCalled = false + this.start() + } + } + + public async exit(): Promise { + this.exitCalled = true + if (this.proc) { + this.proc.kill('SIGTERM') + const timeout = setTimeout(() => { + this.logger.warn( + `GradidoNode couldn't exit graceful after ${GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS} milliseconds with SIGTERM, killing with SIGKILL`, + ) + this.proc?.kill('SIGKILL') + }, GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS) + try { + await this.proc.exited + } catch (error) { + this.logger.error(`GradidoNodeProcess exit error: ${error}`) + } finally { + clearTimeout(timeout) + } + } else { + return Promise.resolve() + } + } +} diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index 6b2a3b1a2..0547f0c8a 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -1,5 +1,12 @@ +import path from 'node:path' + export const LOG4JS_BASE_CATEGORY = 'dlt' // 7 days export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 // 10 minutes export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE = 1000 * 60 * 10 + +export const GRADIDO_NODE_RUNTIME_PATH = path.join(__dirname, 'gradido_node', 'bin', 'GradidoNode') +// if last start was less than this time, do not restart +export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30 +export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 1000 diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 2ce01dcee..027dfc364 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -78,6 +78,7 @@ export const configSchema = v.object({ ), '8340', ), + DLT_NODE_SERVER_VERSION: v.optional(v.string('The version of the DLT node server'), '0.9.0'), PORT: v.optional( v.pipe( v.string('A valid port on which the backend server is running'), From 3bdc99b203a5d7f0b78518ce76be310e3c4e97ce Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 14:43:47 +0200 Subject: [PATCH 068/226] setup gradido node --- dlt-connector/.gitignore | 1 + dlt-connector/bun.lock | 3 + dlt-connector/package.json | 1 + dlt-connector/src/bootstrap/init.ts | 4 + .../src/bootstrap/initGradidoNode.ts | 89 +++++++++++++++++++ .../client/GradidoNode/GradidoNodeClient.ts | 2 +- .../client/GradidoNode/GradidoNodeProcess.ts | 13 +-- .../src/client/GradidoNode/communities.ts | 84 +++++++++++++++++ .../src/client/backend/BackendClient.ts | 21 ++++- dlt-connector/src/client/backend/graphql.ts | 33 ++++--- dlt-connector/src/client/hiero/HieroClient.ts | 13 +++ dlt-connector/src/config/const.ts | 11 ++- dlt-connector/src/config/schema.ts | 10 ++- .../sendToHiero/SendToHiero.context.ts | 15 +++- dlt-connector/src/server/index.test.ts | 6 ++ dlt-connector/src/server/index.ts | 3 + dlt-connector/src/utils/filesystem.ts | 30 +++++++ 17 files changed, 317 insertions(+), 22 deletions(-) create mode 100644 dlt-connector/src/bootstrap/initGradidoNode.ts create mode 100644 dlt-connector/src/client/GradidoNode/communities.ts create mode 100644 dlt-connector/src/utils/filesystem.ts diff --git a/dlt-connector/.gitignore b/dlt-connector/.gitignore index 5435dd5ff..4c6422640 100644 --- a/dlt-connector/.gitignore +++ b/dlt-connector/.gitignore @@ -7,3 +7,4 @@ package-json.lock coverage # emacs *~ +gradido_node \ No newline at end of file diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 7ea3a4eab..a60a02798 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -13,6 +13,7 @@ "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", + "async-mutex": "^0.5.0", "dotenv": "^10.0.0", "elysia": "1.3.8", "graphql-request": "^7.2.0", @@ -306,6 +307,8 @@ "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], + "async-mutex": ["async-mutex@0.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 7dc4e590d..da30cf58d 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -26,6 +26,7 @@ "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", + "async-mutex": "^0.5.0", "dotenv": "^10.0.0", "elysia": "1.3.8", "graphql-request": "^7.2.0", diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index c41553594..13b77783c 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -8,6 +8,7 @@ import { SendToHieroContext } from '../interactions/sendToHiero/SendToHiero.cont import { Community, communitySchema } from '../schemas/transaction.schema' import { isPortOpenRetry } from '../utils/network' import { type AppContext, type AppContextClients } from './appContext' +import { initGradidoNode } from './initGradidoNode' export function loadConfig(): Logger { // configure log4js @@ -74,6 +75,9 @@ export async function checkGradidoNode( logger: Logger, homeCommunity: Community, ): Promise { + // check if gradido node is running, if not setup and start it + await initGradidoNode(clients) + // ask gradido node if community blockchain was created try { if ( diff --git a/dlt-connector/src/bootstrap/initGradidoNode.ts b/dlt-connector/src/bootstrap/initGradidoNode.ts new file mode 100644 index 000000000..3be2e130c --- /dev/null +++ b/dlt-connector/src/bootstrap/initGradidoNode.ts @@ -0,0 +1,89 @@ +import { execSync } from 'node:child_process' +import fs from 'node:fs' +import path from 'node:path' +import { gunzipSync } from 'node:zlib' +import { getLogger } from 'log4js' +import { exportCommunities } from '../client/GradidoNode/communities' +import { GradidoNodeProcess } from '../client/GradidoNode/GradidoNodeProcess' +import { HieroClient } from '../client/hiero/HieroClient' +import { CONFIG } from '../config' +import { + GRADIDO_NODE_HOME_FOLDER_NAME, + GRADIDO_NODE_RUNTIME_PATH, + LOG4JS_BASE_CATEGORY, +} from '../config/const' +import { checkFileExist, checkPathExist } from '../utils/filesystem' +import { isPortOpen } from '../utils/network' +import { AppContextClients } from './appContext' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.bootstrap.initGradidoNode`) + +export async function initGradidoNode(clients: AppContextClients): Promise { + const url = `http://localhost:${CONFIG.DLT_NODE_SERVER_PORT}` + const isOpen = await isPortOpen(url) + if (isOpen) { + logger.info(`GradidoNode is already running on ${url}`) + return + } + + const gradidoNodeHomeFolder = path.join( + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + GRADIDO_NODE_HOME_FOLDER_NAME, + ) + // check folder, create when missing + checkPathExist(gradidoNodeHomeFolder, true) + + await Promise.all([ + // write Hedera Address Book + exportHederaAddressbooks(gradidoNodeHomeFolder, clients.hiero), + // check GradidoNode Runtime, download when missing + ensureGradidoNodeRuntimeAvailable(GRADIDO_NODE_RUNTIME_PATH), + // export communities to GradidoNode Folder + exportCommunities(gradidoNodeHomeFolder, clients.backend), + ]) + GradidoNodeProcess.getInstance().start() +} + +async function exportHederaAddressbooks( + homeFolder: string, + hieroClient: HieroClient, +): Promise { + const networkName = CONFIG.HIERO_HEDERA_NETWORK + const addressBook = await hieroClient.downloadAddressBook() + const addressBookPath = path.join(homeFolder, 'addressbook', `${networkName}.pb`) + checkPathExist(path.dirname(addressBookPath), true) + fs.writeFileSync(addressBookPath, addressBook.toBytes()) +} + +async function ensureGradidoNodeRuntimeAvailable(runtimeFileName: string): Promise { + const runtimeFolder = path.dirname(runtimeFileName) + checkPathExist(runtimeFolder, true) + logger.debug(`GradidoNode Runtime: ${runtimeFileName}`) + if (!checkFileExist(runtimeFileName)) { + const runtimeArchiveFilename = createGradidoNodeRuntimeArchiveFilename() + const downloadUrl = new URL( + `https://github.com/gradido/gradido_node/releases/download/v${CONFIG.DLT_GRADIDO_NODE_SERVER_VERSION}/${runtimeArchiveFilename}`, + ) + logger.debug(`download GradidoNode Runtime from ${downloadUrl}`) + const archive = await fetch(downloadUrl) + if (!archive.ok) { + throw new Error(`Failed to download GradidoNode Runtime: ${archive.statusText}`) + } + const compressedBuffer = await archive.arrayBuffer() + if (process.platform === 'win32') { + fs.writeFileSync(runtimeFileName, gunzipSync(Buffer.from(compressedBuffer))) + } else { + const archivePath = path.join(runtimeFolder, runtimeArchiveFilename) + logger.debug(`GradidoNode Runtime Archive: ${archivePath}`) + fs.writeFileSync(archivePath, Buffer.from(compressedBuffer)) + execSync(`tar -xzf ${archivePath}`, { cwd: runtimeFolder }) + } + } +} + +function createGradidoNodeRuntimeArchiveFilename(): string { + const version = CONFIG.DLT_GRADIDO_NODE_SERVER_VERSION + const platform: string = process.platform + const fileEnding = platform === 'win32' ? 'zip' : 'tar.gz' + return `gradido_node-v${version}-${platform}-${process.arch}.${fileEnding}` +} diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index 3bd3bab51..d66a58887 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -40,7 +40,7 @@ export class GradidoNodeClient { private constructor() { this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNodeClient`) - this.urlValue = `http://localhost:${CONFIG.DLT_NODE_SERVER_PORT}` + this.urlValue = `http://localhost:${CONFIG.DLT_NODE_SERVER_PORT}/api` this.logger.addContext('url', this.urlValue) this.client = new JsonRpcClient({ url: this.urlValue, diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index ad25c2461..d6f5237bf 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -52,12 +52,13 @@ export class GradidoNodeProcess { env: { CLIENTS_HIERO_NETWORKTYPE: CONFIG.HIERO_HEDERA_NETWORK, SERVER_JSON_RPC_PORT: CONFIG.DLT_NODE_SERVER_PORT.toString(), + HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, }, onExit(proc, exitCode, signalCode, error) { logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`) if (error) { logger.error(`GradidoNodeProcess exit error: ${error}`) - if (logger.isDebugEnabled() && proc.stderr) { + /*if (logger.isDebugEnabled() && proc.stderr) { // print error messages from GradidoNode in our own log if debug is enabled proc.stderr .getReader() @@ -65,9 +66,9 @@ export class GradidoNodeProcess { .then((chunk) => { logger.debug(chunk.value?.toString()) }) - } + }*/ } - logger.debug(`ressource usage: ${proc?.resourceUsage()}`) + logger.debug(`ressource usage: ${JSON.stringify(proc?.resourceUsage(), null, 2)}`) const gradidoNodeProcess = GradidoNodeProcess.getInstance() gradidoNodeProcess.proc = null if ( @@ -80,8 +81,10 @@ export class GradidoNodeProcess { gradidoNodeProcess.start() } }, - stdout: 'ignore', - stderr: logger.isDebugEnabled() ? 'pipe' : 'ignore', + /*stdout: 'ignore', + stderr: logger.isDebugEnabled() ? 'pipe' : 'ignore',*/ + stdout: 'inherit', + stderr: 'inherit', }) } diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts new file mode 100644 index 000000000..d25ed4dd4 --- /dev/null +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -0,0 +1,84 @@ +import fs from 'node:fs' +import path from 'node:path' +import { Mutex } from 'async-mutex' +import { getLogger } from 'log4js' +import { CONFIG } from '../../config' +import { GRADIDO_NODE_HOME_FOLDER_NAME, LOG4JS_BASE_CATEGORY } from '../../config/const' +import { HieroId } from '../../schemas/typeGuard.schema' +import { checkFileExist, checkPathExist } from '../../utils/filesystem' +import { BackendClient } from '../backend/BackendClient' +import { GradidoNodeProcess } from './GradidoNodeProcess' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.GradidoNode.communities`) +const ensureCommunitiesAvailableMutex: Mutex = new Mutex() + +// prototype, later add api call to gradido dlt node server for adding/updating communities +type CommunityForDltNodeServer = { + communityId: string + hieroTopicId: string + alias: string + folder: string +} + +export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]): Promise { + const release = await ensureCommunitiesAvailableMutex.acquire() + try { + const homeFolder = path.join( + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + GRADIDO_NODE_HOME_FOLDER_NAME, + ) + if (!checkCommunityAvailable(communityTopicIds, homeFolder)) { + await exportCommunities(homeFolder, BackendClient.getInstance()) + return GradidoNodeProcess.getInstance().restart() + } + } finally { + release() + } +} + +export async function exportCommunities(homeFolder: string, client: BackendClient): Promise { + const communities = await client.getReachableCommunities() + const communitiesPath = path.join(homeFolder, 'communities.json') + checkPathExist(path.dirname(communitiesPath), true) + // make sure communityName is unique + const communityName = new Set() + const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] + for (const com of communities) { + if (!com.uuid || !com.hieroTopicId) { + continue + } + // use name as alias if not empty and unique, otherwise use uuid + let alias = com.name + if (!alias || communityName.has(alias)) { + alias = com.uuid + } + communityName.add(alias) + communitiesForDltNodeServer.push({ + communityId: com.uuid, + hieroTopicId: com.hieroTopicId, + alias, + // use only alpha-numeric chars for folder name + folder: alias.replace(/[^a-zA-Z0-9]/g, '_'), + }) + } + fs.writeFileSync(communitiesPath, JSON.stringify(communitiesForDltNodeServer, null, 2)) + logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`) +} + +export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder: string): boolean { + const communitiesPath = path.join(homeFolder, 'communities.json') + if (!checkFileExist(communitiesPath)) { + return false + } + const communities = JSON.parse(fs.readFileSync(communitiesPath, 'utf-8')) + let foundCount = 0 + for (const community of communities) { + if (communityTopicIds.includes(community.hieroTopicId)) { + foundCount++ + if (foundCount >= communityTopicIds.length) { + return true + } + } + } + return false +} diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index cee82769a..7f779fd73 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -5,7 +5,11 @@ import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' -import { homeCommunityGraphqlQuery, setHomeCommunityTopicId } from './graphql' +import { + getReachableCommunities, + homeCommunityGraphqlQuery, + setHomeCommunityTopicId, +} from './graphql' import { type Community, communitySchema } from './output.schema' // Source: https://refactoring.guru/design-patterns/singleton/typescript/example @@ -42,7 +46,7 @@ export class BackendClient { } public get url(): string { - return this.url + return this.urlValue } /** @@ -84,6 +88,19 @@ export class BackendClient { return v.parse(communitySchema, data.updateHomeCommunity) } + public async getReachableCommunities(): Promise { + this.logger.info('get reachable communities on backend') + const { data, errors } = await this.client.rawRequest<{ reachableCommunities: Community[] }>( + getReachableCommunities, + {}, + await this.getRequestHeader(), + ) + if (errors) { + throw errors[0] + } + return v.parse(v.array(communitySchema), data.reachableCommunities) + } + private async getRequestHeader(): Promise<{ authorization: string }> { diff --git a/dlt-connector/src/client/backend/graphql.ts b/dlt-connector/src/client/backend/graphql.ts index 11d1eb099..03a4a3544 100644 --- a/dlt-connector/src/client/backend/graphql.ts +++ b/dlt-connector/src/client/backend/graphql.ts @@ -4,27 +4,40 @@ import { gql } from 'graphql-request' * Schema Definitions for graphql requests */ +const communityFragment = gql` + fragment Community_common on Community { + uuid + name + hieroTopicId + foreign + creationDate + } +` + // graphql query for getting home community in tune with community schema export const homeCommunityGraphqlQuery = gql` query { homeCommunity { - uuid - name - hieroTopicId - foreign - creationDate + ...Community_common } } + ${communityFragment} ` export const setHomeCommunityTopicId = gql` mutation ($uuid: String!, $hieroTopicId: String){ updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { - uuid - name - hieroTopicId - foreign - creationDate + ...Community_common } } + ${communityFragment} +` + +export const getReachableCommunities = gql` + query { + reachableCommunities { + ...Community_common + } + } + ${communityFragment} ` diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index e48eefc92..33a208b78 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -1,8 +1,11 @@ import { AccountBalance, AccountBalanceQuery, + AddressBookQuery, Client, + FileId, LocalProvider, + NodeAddressBook, PrivateKey, TopicCreateTransaction, TopicId, @@ -166,6 +169,16 @@ export class HieroClient { return v.parse(hieroIdSchema, createReceipt.topicId?.toString()) } + public async downloadAddressBook(): Promise { + const query = new AddressBookQuery().setFileId(FileId.ADDRESS_BOOK) + try { + return await query.execute(this.client) + } catch (e) { + this.logger.error(e) + throw e + } + } + public async updateTopic(topicId: HieroId): Promise { this.logger.addContext('topicId', topicId.toString()) let transaction = new TopicUpdateTransaction() diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index 0547f0c8a..9e0b93b46 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -6,7 +6,16 @@ export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE = 1000 * 60 * 60 * 24 * 7 // 10 minutes export const MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_SEND_MESSAGE = 1000 * 60 * 10 -export const GRADIDO_NODE_RUNTIME_PATH = path.join(__dirname, 'gradido_node', 'bin', 'GradidoNode') +export const GRADIDO_NODE_RUNTIME_PATH = path.join( + __dirname, + '..', + '..', + 'gradido_node', + 'bin', + 'GradidoNode', +) // if last start was less than this time, do not restart export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30 export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 1000 +// currently hard coded in gradido node, update in future +export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido' diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 027dfc364..67a43383d 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -1,3 +1,4 @@ +import path from 'node:path' import { MemoryBlock } from 'gradido-blockchain-js' import * as v from 'valibot' @@ -78,7 +79,14 @@ export const configSchema = v.object({ ), '8340', ), - DLT_NODE_SERVER_VERSION: v.optional(v.string('The version of the DLT node server'), '0.9.0'), + DLT_GRADIDO_NODE_SERVER_VERSION: v.optional( + v.string('The version of the DLT node server'), + '0.9.0', + ), + DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( + v.string('The home folder for the gradido dlt node server'), + path.join(__dirname, '..', '..', 'gradido_node'), + ), PORT: v.optional( v.pipe( v.string('A valid port on which the backend server is running'), diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 14427cacf..5b5f1f629 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -7,6 +7,7 @@ import { } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import * as v from 'valibot' +import { ensureCommunitiesAvailable } from '../../client/GradidoNode/communities' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { InputTransactionType } from '../../data/InputTransactionType.enum' @@ -40,7 +41,7 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendT export async function SendToHieroContext( input: TransactionInput | CommunityInput, ): Promise { - const role = chooseCorrectRole(input) + const role = await chooseCorrectRole(input) const builder = await role.getGradidoTransactionBuilder() if (builder.isCrossCommunityTransaction()) { // build cross group transaction @@ -107,9 +108,13 @@ async function sendViaHiero( } // choose correct role based on transaction type and input type -function chooseCorrectRole(input: TransactionInput | CommunityInput): AbstractTransactionRole { +async function chooseCorrectRole( + input: TransactionInput | CommunityInput, +): Promise { const communityParsingResult = v.safeParse(communitySchema, input) if (communityParsingResult.success) { + // make sure gradido node knows community + await ensureCommunitiesAvailable([communityParsingResult.output.hieroTopicId]) return new CommunityRootTransactionRole(communityParsingResult.output) } @@ -121,6 +126,12 @@ function chooseCorrectRole(input: TransactionInput | CommunityInput): AbstractTr }) throw new Error('invalid input') } + // make sure gradido node knows communities + const communityTopicIds = [ + transactionParsingResult.output.user.communityTopicId, + transactionParsingResult.output.linkedUser?.communityTopicId, + ].filter((id): id is HieroId => id !== undefined) + await ensureCommunitiesAvailable(communityTopicIds) const transaction = transactionParsingResult.output switch (transaction.type) { diff --git a/dlt-connector/src/server/index.test.ts b/dlt-connector/src/server/index.test.ts index 9ec7f236a..4b6b8be76 100644 --- a/dlt-connector/src/server/index.test.ts +++ b/dlt-connector/src/server/index.test.ts @@ -25,6 +25,12 @@ mock.module('../KeyPairCacheManager', () => { } }) +mock.module('../client/GradidoNode/communities', () => ({ + ensureCommunitiesAvailable: () => { + return Promise.resolve() + }, +})) + mock.module('../client/hiero/HieroClient', () => ({ HieroClient: { getInstance: () => ({ diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 406d04d06..191e990d3 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -3,6 +3,7 @@ import { Elysia, status, t } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import * as v from 'valibot' +import { ensureCommunitiesAvailable } from '../client/GradidoNode/communities' import { GradidoNodeClient } from '../client/GradidoNode/GradidoNodeClient' import { LOG4JS_BASE_CATEGORY } from '../config/const' import { KeyPairIdentifierLogic } from '../data/KeyPairIdentifier.logic' @@ -125,6 +126,8 @@ async function isAccountExist(identifierAccount: IdentifierAccountInput): Promis // check and prepare input const startTime = Date.now() const identifierAccountParsed = v.parse(identifierAccountSchema, identifierAccount) + // make sure gradido node knows community + await ensureCommunitiesAvailable([identifierAccountParsed.communityTopicId]) const accountKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic(identifierAccountParsed)) const publicKey = accountKeyPair.getPublicKey() if (!publicKey) { diff --git a/dlt-connector/src/utils/filesystem.ts b/dlt-connector/src/utils/filesystem.ts new file mode 100644 index 000000000..639c1b8a4 --- /dev/null +++ b/dlt-connector/src/utils/filesystem.ts @@ -0,0 +1,30 @@ +import fs from 'node:fs' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../config/const' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.utils.filesystem`) + +export function checkFileExist(filePath: string): boolean { + try { + fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK) + return true + } catch (err) { + logger.debug(`file ${filePath} does not exist: ${err}`) + return false + } +} + +export function checkPathExist(path: string, createIfMissing: boolean = false): boolean { + const exists = checkFileExist(path) + if (exists) { + return true + } + if (createIfMissing) { + logger.info(`create folder ${path}`) + fs.mkdirSync(path, { recursive: true }) + if (!checkPathExist(path)) { + throw new Error(`Failed to create path ${path}`) + } + } + return false +} From 04af2ebec9252a563e6ca88308187a255ce7c95c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 14:48:40 +0200 Subject: [PATCH 069/226] give it more time for gracefull exit --- dlt-connector/src/config/const.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index 9e0b93b46..dc4b0177c 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -16,6 +16,6 @@ export const GRADIDO_NODE_RUNTIME_PATH = path.join( ) // if last start was less than this time, do not restart export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30 -export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 1000 +export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 10000 // currently hard coded in gradido node, update in future export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido' From 181c1d28fc4d99312108e5265f591225f4fa744b Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 15:28:21 +0200 Subject: [PATCH 070/226] fix for windows --- dlt-connector/bun.lock | 3 +++ dlt-connector/package.json | 1 + dlt-connector/src/bootstrap/initGradidoNode.ts | 6 +++--- dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts | 1 + dlt-connector/src/client/backend/graphql.ts | 7 +++++-- dlt-connector/src/utils/filesystem.ts | 2 +- 6 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index a60a02798..b1929bed8 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -13,6 +13,7 @@ "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", + "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", "elysia": "1.3.8", @@ -285,6 +286,8 @@ "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "adm-zip": ["adm-zip@0.5.16", "", {}, "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index da30cf58d..1271726ec 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -26,6 +26,7 @@ "@sinclair/typemap": "^0.10.1", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", + "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", "elysia": "1.3.8", diff --git a/dlt-connector/src/bootstrap/initGradidoNode.ts b/dlt-connector/src/bootstrap/initGradidoNode.ts index 3be2e130c..263bed249 100644 --- a/dlt-connector/src/bootstrap/initGradidoNode.ts +++ b/dlt-connector/src/bootstrap/initGradidoNode.ts @@ -1,7 +1,6 @@ import { execSync } from 'node:child_process' import fs from 'node:fs' import path from 'node:path' -import { gunzipSync } from 'node:zlib' import { getLogger } from 'log4js' import { exportCommunities } from '../client/GradidoNode/communities' import { GradidoNodeProcess } from '../client/GradidoNode/GradidoNodeProcess' @@ -15,6 +14,7 @@ import { import { checkFileExist, checkPathExist } from '../utils/filesystem' import { isPortOpen } from '../utils/network' import { AppContextClients } from './appContext' +import AdmZip from 'adm-zip' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.bootstrap.initGradidoNode`) @@ -58,7 +58,6 @@ async function exportHederaAddressbooks( async function ensureGradidoNodeRuntimeAvailable(runtimeFileName: string): Promise { const runtimeFolder = path.dirname(runtimeFileName) checkPathExist(runtimeFolder, true) - logger.debug(`GradidoNode Runtime: ${runtimeFileName}`) if (!checkFileExist(runtimeFileName)) { const runtimeArchiveFilename = createGradidoNodeRuntimeArchiveFilename() const downloadUrl = new URL( @@ -71,7 +70,8 @@ async function ensureGradidoNodeRuntimeAvailable(runtimeFileName: string): Promi } const compressedBuffer = await archive.arrayBuffer() if (process.platform === 'win32') { - fs.writeFileSync(runtimeFileName, gunzipSync(Buffer.from(compressedBuffer))) + const zip = new AdmZip(Buffer.from(compressedBuffer)) + zip.extractAllTo(runtimeFolder, true) } else { const archivePath = path.join(runtimeFolder, runtimeArchiveFilename) logger.debug(`GradidoNode Runtime Archive: ${archivePath}`) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index d6f5237bf..eb2bf6b66 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -52,6 +52,7 @@ export class GradidoNodeProcess { env: { CLIENTS_HIERO_NETWORKTYPE: CONFIG.HIERO_HEDERA_NETWORK, SERVER_JSON_RPC_PORT: CONFIG.DLT_NODE_SERVER_PORT.toString(), + USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, }, onExit(proc, exitCode, signalCode, error) { diff --git a/dlt-connector/src/client/backend/graphql.ts b/dlt-connector/src/client/backend/graphql.ts index 03a4a3544..fafd77fcd 100644 --- a/dlt-connector/src/client/backend/graphql.ts +++ b/dlt-connector/src/client/backend/graphql.ts @@ -27,10 +27,13 @@ export const homeCommunityGraphqlQuery = gql` export const setHomeCommunityTopicId = gql` mutation ($uuid: String!, $hieroTopicId: String){ updateHomeCommunity(uuid: $uuid, hieroTopicId: $hieroTopicId) { - ...Community_common + uuid + name + hieroTopicId + foreign + creationDate } } - ${communityFragment} ` export const getReachableCommunities = gql` diff --git a/dlt-connector/src/utils/filesystem.ts b/dlt-connector/src/utils/filesystem.ts index 639c1b8a4..29a3a7519 100644 --- a/dlt-connector/src/utils/filesystem.ts +++ b/dlt-connector/src/utils/filesystem.ts @@ -9,7 +9,7 @@ export function checkFileExist(filePath: string): boolean { fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK) return true } catch (err) { - logger.debug(`file ${filePath} does not exist: ${err}`) + // logger.debug(`file ${filePath} does not exist: ${err}`) return false } } From 39ae8966754cd3c716e21a9a54e13cdb7e7d1d82 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 15:31:05 +0200 Subject: [PATCH 071/226] fix lint --- dlt-connector/src/bootstrap/initGradidoNode.ts | 2 +- dlt-connector/src/utils/filesystem.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlt-connector/src/bootstrap/initGradidoNode.ts b/dlt-connector/src/bootstrap/initGradidoNode.ts index 263bed249..7c652a667 100644 --- a/dlt-connector/src/bootstrap/initGradidoNode.ts +++ b/dlt-connector/src/bootstrap/initGradidoNode.ts @@ -1,6 +1,7 @@ import { execSync } from 'node:child_process' import fs from 'node:fs' import path from 'node:path' +import AdmZip from 'adm-zip' import { getLogger } from 'log4js' import { exportCommunities } from '../client/GradidoNode/communities' import { GradidoNodeProcess } from '../client/GradidoNode/GradidoNodeProcess' @@ -14,7 +15,6 @@ import { import { checkFileExist, checkPathExist } from '../utils/filesystem' import { isPortOpen } from '../utils/network' import { AppContextClients } from './appContext' -import AdmZip from 'adm-zip' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.bootstrap.initGradidoNode`) diff --git a/dlt-connector/src/utils/filesystem.ts b/dlt-connector/src/utils/filesystem.ts index 29a3a7519..ea2d64e39 100644 --- a/dlt-connector/src/utils/filesystem.ts +++ b/dlt-connector/src/utils/filesystem.ts @@ -8,8 +8,8 @@ export function checkFileExist(filePath: string): boolean { try { fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK) return true - } catch (err) { - // logger.debug(`file ${filePath} does not exist: ${err}`) + } catch (_err) { + // logger.debug(`file ${filePath} does not exist: ${_err}`) return false } } From 49051d4bed523e6f2dbc7696eebca9f40fe7344d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 15:32:00 +0200 Subject: [PATCH 072/226] add missing type --- dlt-connector/bun.lock | 3 +++ dlt-connector/package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index b1929bed8..46e566b54 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -11,6 +11,7 @@ "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", + "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", @@ -250,6 +251,8 @@ "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + "@types/adm-zip": ["@types/adm-zip@0.5.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 1271726ec..e1bef07c9 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -24,6 +24,7 @@ "@hashgraph/sdk": "^2.70.0", "@sinclair/typebox": "^0.34.33", "@sinclair/typemap": "^0.10.1", + "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", From f19c85ceb5c12f4809c99e58e2d827881d3bf79c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 16:27:49 +0200 Subject: [PATCH 073/226] first draft --- deployment/bare_metal/.env.dist | 5 +- .../sites-available/gradido-dlt.conf.template | 46 ++++++++++++++++++ .../sites-available/gradido.conf.ssl.template | 48 +------------------ deployment/bare_metal/start.sh | 14 +++++- dlt-connector/src/config/schema.ts | 4 ++ inspector | 2 +- 6 files changed, 69 insertions(+), 50 deletions(-) create mode 100644 deployment/bare_metal/nginx/sites-available/gradido-dlt.conf.template diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index f9a111feb..76d6a76f5 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -86,9 +86,10 @@ FEDERATION_COMMUNITY_APIS=1_0 GDT_ACTIVE=false # DLT-Connector (still in develop) -DLT_CONNECTOR=true +DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 -NODE_SERVER_URL=http://localhost:8340/api +DLT_NODE_SERVER_PORT=8340 +DLT_NODE_SERVER_URL=$URL_PROTOCOL://$COMMUNITY_HOST/dlt # used for combining a newsletter on klicktipp with this gradido community # if used, user will be subscribed on register and can unsubscribe in his account diff --git a/deployment/bare_metal/nginx/sites-available/gradido-dlt.conf.template b/deployment/bare_metal/nginx/sites-available/gradido-dlt.conf.template new file mode 100644 index 000000000..0fd2ba985 --- /dev/null +++ b/deployment/bare_metal/nginx/sites-available/gradido-dlt.conf.template @@ -0,0 +1,46 @@ + # Blockchain Explorer + location /inspector { + limit_req zone=frontend burst=30 nodelay; + limit_conn addr 20; + alias $PROJECT_ROOT/inspector/build/; + index index.html; + + # caching rules for assets + # static assets + location ~* \.(?:woff2?|ttf|otf|eot|jpg|jpeg|png|gif|svg|webp|ico)$ { + # keep assets for a week + add_header Cache-Control "public, max-age=604800"; + try_files $uri =404; + } + # hashed assets + location ~* \.(?:js|css|json)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + try_files $uri =404; + } + + try_files $uri $uri/ /index.html = 404; + + # don't cache index.html + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires 0; + + access_log $GRADIDO_LOG_PATH/nginx-access.inspector.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.inspector.log warn; + } + + # Gradido-Node + location /dlt { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://127.0.0.1:$DLT_NODE_SERVER_PORT/api; + proxy_redirect off; + + access_log $GRADIDO_LOG_PATH/nginx-access.dlt.log gradido_log; + error_log $GRADIDO_LOG_PATH/nginx-error.dlt.log warn; + } \ No newline at end of file diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index fd54a27cc..72ac17390 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -101,22 +101,6 @@ server { error_log $GRADIDO_LOG_PATH/nginx-error.backend.log warn; } - # Gradido-Node - location /dlt { - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - - proxy_pass http://127.0.0.1:8340/api/; - proxy_redirect off; - - access_log $GRADIDO_LOG_PATH/nginx-access.dlt.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.dlt.log warn; - } - # Backend webhooks location /hook { limit_req zone=backend burst=20 nodelay; @@ -213,36 +197,8 @@ server { error_log $GRADIDO_LOG_PATH/nginx-error.admin.log warn; } - # Admin Frontend - location /inspector { - limit_req zone=frontend burst=30 nodelay; - limit_conn addr 20; - alias $PROJECT_ROOT/inspector/build/; - index index.html; - - # caching rules for assets - # static assets - location ~* \.(?:woff2?|ttf|otf|eot|jpg|jpeg|png|gif|svg|webp|ico)$ { - # keep assets for a week - add_header Cache-Control "public, max-age=604800"; - try_files $uri =404; - } - # hashed assets - location ~* \.(?:js|css|json)$ { - add_header Cache-Control "public, max-age=31536000, immutable"; - try_files $uri =404; - } - - try_files $uri $uri/ /index.html = 404; - - # don't cache index.html - add_header Cache-Control "no-cache, no-store, must-revalidate"; - add_header Pragma "no-cache"; - add_header Expires 0; - - access_log $GRADIDO_LOG_PATH/nginx-access.inspector.log gradido_log; - error_log $GRADIDO_LOG_PATH/nginx-error.inspector.log warn; - } + # dlt + $DLT_NGINX_CONF # Federation $FEDERATION_NGINX_CONF diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index ca9f7c57a..b228e117e 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -185,6 +185,7 @@ cd $PROJECT_ROOT git fetch --all git checkout $BRANCH_NAME git pull +git submodule update --init --recursive export BUILD_COMMIT="$(git rev-parse HEAD)" # install missing dependencies @@ -213,6 +214,16 @@ unset FEDERATION_APIVERSION unset FEDERATION_PORT log_step "====================================================================================================" +# prepare inspector and gradido dlt node nginx config blocks if enabled +if [ "$DLT_CONNECTOR" = true ] ; then + log_step "prepare inspector and dlt gradido node nginx config block" + envsubst '$DLT_NODE_SERVER_PORT' < $NGINX_CONFIG_DIR/gradido-dlt.conf.template >> $NGINX_CONFIG_DIR/gradido-dlt.conf + export DLT_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-dlt.conf) + rm $NGINX_CONFIG_DIR/gradido-dlt.conf +else + export DLT_NGINX_CONF="# dlt is disabled" +fi + # *** 2nd read gradido-federation.conf file in env variable to be replaced in 3rd step export FEDERATION_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-federation.conf.locations) @@ -222,8 +233,9 @@ case "$URL_PROTOCOL" in 'https') TEMPLATE_FILE="gradido.conf.ssl.template" ;; *) TEMPLATE_FILE="gradido.conf.template" ;; esac -envsubst '$FEDERATION_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp +envsubst '$FEDERATION_NGINX_CONF,$DLT_NGINX_CONF' < $NGINX_CONFIG_DIR/$TEMPLATE_FILE > $NGINX_CONFIG_DIR/gradido.conf.tmp unset FEDERATION_NGINX_CONF +unset DLT_NGINX_CONF envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $NGINX_CONFIG_DIR/gradido.conf.tmp > $NGINX_CONFIG_DIR/gradido.conf rm $NGINX_CONFIG_DIR/gradido.conf.tmp rm $NGINX_CONFIG_DIR/gradido-federation.conf.locations diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 08eeb2b80..185d0b899 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -20,6 +20,10 @@ export const configSchema = v.object({ ), '6010', ), + DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( + v.string('The home folder for the gradido dlt node server'), + '~/.gradido', // currently hardcoded in dlt gradido node server + ), JWT_SECRET: v.optional( v.pipe( v.string('The JWT secret for connecting to the backend'), diff --git a/inspector b/inspector index ab1fcc035..8e29fd44e 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit ab1fcc03546a1e98e4f236243d6cef1ae4a566d6 +Subproject commit 8e29fd44efbede40649f850a674118e2d4379897 From 437b7421d7d0be913d3025366bd6007b3a00a28e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 16:39:58 +0200 Subject: [PATCH 074/226] fix test --- deployment/bare_metal/start.sh | 19 +++++++++++-------- dlt-connector/.env.dist | 13 +++++++------ dlt-connector/src/config/schema.ts | 4 ---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index b228e117e..03bf44f8d 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -256,6 +256,7 @@ MODULES=( admin dht-node federation + inspector ) if [ "$FAST_MODE" = false ] ; then @@ -300,15 +301,17 @@ log_step 'build all modules' turbo build --env-mode=loose --concurrency=$(nproc) # build inspector and dlt-connector -log_step 'build inspector' -cd $PROJECT_ROOT/inspector -bun install -bun run build +if [ "$DLT_CONNECTOR" = true ]; then + log_step 'build inspector' + cd $PROJECT_ROOT/inspector + bun install + bun run build -log_step 'build dlt-connector' -cd $PROJECT_ROOT/dlt-connector -bun install -bun run build + log_step 'build dlt-connector' + cd $PROJECT_ROOT/dlt-connector + bun install + bun run build +fi # database log_step 'Updating database' diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 8253699ca..165ca7bd0 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -1,19 +1,20 @@ -CONFIG_VERSION=v6.2024-02-20 - # SET LOG LEVEL AS NEEDED IN YOUR .ENV # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal # LOG_LEVEL=info -# IOTA -IOTA_API_URL=https://chrysalis-nodes.iota.org -IOTA_COMMUNITY_ALIAS=GRADIDO: TestHelloWelt2 -IOTA_HOME_COMMUNITY_SEED=aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 +HOME_COMMUNITY_SEED=aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899 # DLT-Connector DLT_CONNECTOR_PORT=6010 # Gradido Node Server URL DLT_NODE_SERVER_PORT=8340 +DLT_GRADIDO_NODE_SERVER_VERSION=0.9.0 + +HIERO_ACTIVE=true +HIERO_HEDERA_NETWORK=testnet +HIERO_OPERATOR_ID="YOUR_OPERATOR_ID" +HIERO_OPERATOR_KEY="YOUR_OPERATOR_ED25519_PRIVATE_KEY_IN_DER_FORMAT" # Gradido Blockchain GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=21ffbbc616fe diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 3862a0dd5..67a43383d 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -21,10 +21,6 @@ export const configSchema = v.object({ ), '6010', ), - DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( - v.string('The home folder for the gradido dlt node server'), - '~/.gradido', // currently hardcoded in dlt gradido node server - ), JWT_SECRET: v.optional( v.pipe( v.string('The JWT secret for connecting to the backend'), From 72fadb91c4759eed823d251f4e568bcb554987e2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 16:45:14 +0200 Subject: [PATCH 075/226] missing if --- deployment/bare_metal/start.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 03bf44f8d..5976525c8 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -256,8 +256,10 @@ MODULES=( admin dht-node federation - inspector ) +if [ "$DLT_CONNECTOR" = true ] ; then + MODULES+=("inspector") +fi if [ "$FAST_MODE" = false ] ; then log_step 'Clean tmp, bun and yarn cache' From 5f832fb89aea98d2cc9baa847dd967b712f46d68 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 16:53:27 +0200 Subject: [PATCH 076/226] case with missing .env --- deployment/bare_metal/start.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 5976525c8..42b16a2f3 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -290,7 +290,10 @@ fi log_step 'Regenerate .env files' for dir in "${MODULES[@]}"; do base="$PROJECT_ROOT/$dir" - cp -f $base/.env $base/.env.bak + # Backup .env file if exists + if [ -f "$base/.env" ]; then + cp -f $base/.env $base/.env.bak + fi envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $base/.env.template > $base/.env done From a9339c1e6c6627efee584f613c5c2eaccd4e3c78 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 17:03:47 +0200 Subject: [PATCH 077/226] fixes for deploy script --- deployment/bare_metal/.env.dist | 10 ++-------- deployment/bare_metal/start.sh | 1 + dlt-connector/.env.template | 25 +++++++++++++++++++++++++ inspector | 2 +- 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 dlt-connector/.env.template diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index abe2d0202..dc11fff71 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -22,14 +22,6 @@ EMAIL_CODE_VALID_TIME=1440 # also used for password reset code EMAIL_CODE_REQUEST_TIME=10 -# Need to adjust by updates -# config versions -DATABASE_CONFIG_VERSION=v1.2022-03-18 -BACKEND_CONFIG_VERSION=v23.2024-04-04 -FRONTEND_CONFIG_VERSION=v6.2024-02-27 -ADMIN_CONFIG_VERSION=v2.2024-01-04 -FEDERATION_CONFIG_VERSION=v2.2023-08-24 -FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17 FEDERATION_DHT_TOPIC=GRADIDO_HUB # Need adjustments for test system @@ -85,6 +77,8 @@ FEDERATION_COMMUNITY_APIS=1_0 # externe gradido services (more added in future) GDT_ACTIVE=false +AUTO_POLL_INTERVAL=30000 + # DLT-Connector (still in develop) DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 42b16a2f3..49e7c728b 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -259,6 +259,7 @@ MODULES=( ) if [ "$DLT_CONNECTOR" = true ] ; then MODULES+=("inspector") + MODULES+=("dlt-connector") fi if [ "$FAST_MODE" = false ] ; then diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template new file mode 100644 index 000000000..963d0169b --- /dev/null +++ b/dlt-connector/.env.template @@ -0,0 +1,25 @@ +# SET LOG LEVEL AS NEEDED IN YOUR .ENV +# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal +# LOG_LEVEL=info + +HOME_COMMUNITY_SEED=$HOME_COMMUNITY_SEED + +# DLT-Connector +DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT + +# Gradido Node Server URL +DLT_NODE_SERVER_PORT=$DLT_NODE_SERVER_PORT +DLT_GRADIDO_NODE_SERVER_VERSION=$DLT_GRADIDO_NODE_SERVER_VERSION + +HIERO_ACTIVE=$HIERO_ACTIVE +HIERO_HEDERA_NETWORK=$HIERO_HEDERA_NETWORK +HIERO_OPERATOR_ID=$HIERO_OPERATOR_ID +HIERO_OPERATOR_KEY=$HIERO_OPERATOR_KEY + +# Gradido Blockchain +GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET +GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY + +# Route to Backend +PORT=$PORT +JWT_SECRET=$JWT_SECRET \ No newline at end of file diff --git a/inspector b/inspector index 8e29fd44e..cf13ca7c3 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 8e29fd44efbede40649f850a674118e2d4379897 +Subproject commit cf13ca7c3fb225a05e9c414ce1691929bef43444 From 5a2e8807a2be1b20937eeb4e9f3dca491fcf5fd6 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 17:19:03 +0200 Subject: [PATCH 078/226] update inspector --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index cf13ca7c3..5e0014f6a 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit cf13ca7c3fb225a05e9c414ce1691929bef43444 +Subproject commit 5e0014f6ad568415eaeec112a37a362a49c29e13 From 69a6c820e2728b58420f372c977a46d5d9fa2786 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 17:23:11 +0200 Subject: [PATCH 079/226] add less to inspector --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index 5e0014f6a..9c57ed032 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 5e0014f6ad568415eaeec112a37a362a49c29e13 +Subproject commit 9c57ed032d2e0523cfb5c6400c3a841147a7f957 From 9c62322be024575317ff08114fd2ecdec30aee9c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 17:24:26 +0200 Subject: [PATCH 080/226] correct path --- deployment/bare_metal/start.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 49e7c728b..cb53206a5 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -317,6 +317,8 @@ if [ "$DLT_CONNECTOR" = true ]; then cd $PROJECT_ROOT/dlt-connector bun install bun run build + + cd $PROJECT_ROOT fi # database From 7085e55d299f53a58a9b3d098c79f3d6a5ebff6e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 25 Oct 2025 17:48:24 +0200 Subject: [PATCH 081/226] small fixes --- deployment/bare_metal/.env.dist | 3 +++ dlt-connector/src/config/schema.ts | 5 ++++- inspector | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index dc11fff71..059822ea4 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -12,6 +12,8 @@ EMAIL_PASSWORD=1234 EMAIL_SMTP_HOST=smtp.lustig.de EMAIL_SMTP_PORT=587 +PORT=4000 + # if set to true allow sending gradidos to another communities FEDERATION_XCOM_SENDCOINS_ENABLED=false @@ -84,6 +86,7 @@ DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 DLT_NODE_SERVER_PORT=8340 DLT_NODE_SERVER_URL=$URL_PROTOCOL://$COMMUNITY_HOST/dlt +DLT_GRADIDO_NODE_SERVER_VERSION=0.9.0 DLT_GRADIDO_NODE_SERVER_HOME_FOLDER=/home/gradido/.gradido # used for combining a newsletter on klicktipp with this gradido community diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 67a43383d..645f07470 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -80,7 +80,10 @@ export const configSchema = v.object({ '8340', ), DLT_GRADIDO_NODE_SERVER_VERSION: v.optional( - v.string('The version of the DLT node server'), + v.pipe( + v.string('The version of the DLT node server, for example: 0.9.0'), + v.regex(/^\d+\.\d+\.\d+$/), + ), '0.9.0', ), DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( diff --git a/inspector b/inspector index 9c57ed032..8b63929c7 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 9c57ed032d2e0523cfb5c6400c3a841147a7f957 +Subproject commit 8b63929c7e73ee5c542e05607213f6c80019cf52 From 09f261c1ebfcaad8e0865b54df291d945fd5df84 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 27 Oct 2025 13:27:49 +0100 Subject: [PATCH 082/226] rollback change, because moved in other pr --- backend/src/federation/validateCommunities.ts | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 3b910b313..ac9334977 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -2,7 +2,6 @@ import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity, getHomeCommunity, - getReachableCommunities, } from 'database' import { IsNull } from 'typeorm' @@ -16,9 +15,6 @@ import { getLogger } from 'log4js' import { startCommunityAuthentication } from './authenticateCommunities' import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view' import { ApiVersionType } from 'core' -import { CONFIG } from '@/config' -import * as path from 'node:path' -import * as fs from 'node:fs' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.validateCommunities`) @@ -87,8 +83,6 @@ export async function validateCommunities(): Promise { logger.error(`Error:`, err) } } - // export communities for gradido dlt node server - await exportCommunitiesToDltNodeServer() } export async function writeJwtKeyPairInHomeCommunity(): Promise { @@ -148,48 +142,3 @@ async function writeForeignCommunity( await DbCommunity.save(com) } } - -// prototype, later add api call to gradido dlt node server for adding/updating communities -type CommunityForDltNodeServer = { - communityId: string - hieroTopicId: string - alias: string - folder: string -} -async function exportCommunitiesToDltNodeServer(): Promise { - if (!CONFIG.DLT_CONNECTOR) { - return Promise.resolve() - } - const folder = CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER - try { - fs.accessSync(folder, fs.constants.R_OK | fs.constants.W_OK) - } catch (err) { - logger.error(`Error: home folder for DLT Gradido Node Server ${folder} does not exist`) - return - } - - const dbComs = await getReachableCommunities(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER * 4) - const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] - // make sure communityName is unique - const communityName = new Set() - dbComs.forEach((com) => { - if (!com.communityUuid || !com.hieroTopicId) { - return - } - let alias = com.name - if (!alias || communityName.has(alias)) { - alias = com.communityUuid - } - communityName.add(alias) - communitiesForDltNodeServer.push({ - communityId: com.communityUuid, - hieroTopicId: com.hieroTopicId, - alias, - // use only alpha-numeric chars for folder name - folder: alias.replace(/[^a-zA-Z0-9]/g, '_') - }) - }) - const dltNodeServerCommunitiesFile = path.join(folder, 'communities.json') - fs.writeFileSync(dltNodeServerCommunitiesFile, JSON.stringify(communitiesForDltNodeServer, null, 2)) - logger.debug(`Written communitiesForDltNodeServer to ${dltNodeServerCommunitiesFile}`) -} From b09dd70e81acc0b28d690e47845a4d71c40ba001 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 28 Oct 2025 09:52:06 +0100 Subject: [PATCH 083/226] update inspector, fix frontend env problem --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index 8b63929c7..c7fc92da3 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 8b63929c7e73ee5c542e05607213f6c80019cf52 +Subproject commit c7fc92da31e80a27558d3887543446079dc55b5e From 9c85b7829f3ab004ab3cd0eb0226903a827a9da3 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 28 Oct 2025 10:03:53 +0100 Subject: [PATCH 084/226] change PORT env variable to BACKEND_PORT to prevent mix-ups with native PORT env from nginx in Docker --- backend/.env.dist | 2 +- backend/.env.template | 2 +- backend/.env.test_e2e | 1 + backend/Dockerfile | 4 +-- backend/src/config/index.ts | 2 +- backend/src/config/schema.ts | 2 +- backend/src/index.ts | 6 ++-- deployment/bare_metal/.env.dist | 10 ++++++- dlt-connector/.env.template | 2 +- .../src/client/backend/BackendClient.ts | 2 +- dlt-connector/src/config/schema.ts | 2 +- docker-compose.override.yml | 20 +++++++++++++ docker-compose.yml | 30 +++++++++++++++++-- 13 files changed, 69 insertions(+), 16 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 8d5ba317c..0860b9c94 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,5 +1,5 @@ # Server -PORT=4000 +BACKEND_PORT=4000 JWT_SECRET=secret123 JWT_EXPIRES_IN=10m GRAPHIQL=false diff --git a/backend/.env.template b/backend/.env.template index 9b0bc7df2..5212d1e1b 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,11 +1,11 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=$BACKEND_CONFIG_VERSION # Server JWT_SECRET=$JWT_SECRET JWT_EXPIRES_IN=$JWT_EXPIRES_IN GRAPHIQL=false GDT_API_URL=$GDT_API_URL +BACKEND_PORT=$BACKEND_PORT # Database DB_HOST=127.0.0.1 diff --git a/backend/.env.test_e2e b/backend/.env.test_e2e index e7f3a29c8..1a6c3a214 100644 --- a/backend/.env.test_e2e +++ b/backend/.env.test_e2e @@ -1,5 +1,6 @@ # Server JWT_EXPIRES_IN=2m +BACKEND_PORT=4000 GDT_ACTIVE=false HUMHUB_ACTIVE=false diff --git a/backend/Dockerfile b/backend/Dockerfile index eeab1ac17..f015350c0 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -17,7 +17,7 @@ ENV BUILD_COMMIT="0000000" ## SET NODE_ENV ENV NODE_ENV=production ## App relevant Envs -ENV PORT="4000" +ENV BACKEND_PORT="4000" ## Timezone ENV TZ=UTC ENV DB_HOST=mariadb @@ -42,7 +42,7 @@ LABEL maintainer="support@gradido.net" # Settings ## Expose Container Port -EXPOSE ${PORT} +EXPOSE ${BACKEND_PORT} ## Workdir RUN mkdir -p ${DOCKER_WORKDIR} diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index b583156b5..f29f0b0f7 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -16,7 +16,7 @@ const logging = { } const server = { - PORT: process.env.PORT ?? 4000, + BACKEND_PORT: process.env.BACKEND_PORT ?? 4000, JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN ?? '10m', REDEEM_JWT_TOKEN_EXPIRATION: process.env.REDEEM_JWT_TOKEN_EXPIRATION ?? '10m', diff --git a/backend/src/config/schema.ts b/backend/src/config/schema.ts index f4e6033ea..4b13b4e64 100644 --- a/backend/src/config/schema.ts +++ b/backend/src/config/schema.ts @@ -260,7 +260,7 @@ export const schema = Joi.object({ }) .description('JWT key for HumHub integration, must be the same as configured in humhub'), - PORT: Joi.number() + BACKEND_PORT: Joi.number() .integer() .min(1024) .max(49151) diff --git a/backend/src/index.ts b/backend/src/index.ts index 283554a9d..db4bf76b5 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -12,12 +12,12 @@ async function main() { const { app } = await createServer(getLogger('apollo')) await writeJwtKeyPairInHomeCommunity() - app.listen(CONFIG.PORT, () => { + app.listen(CONFIG.BACKEND_PORT, () => { // biome-ignore lint/suspicious/noConsole: no need for logging the start message - console.log(`Server is running at http://localhost:${CONFIG.PORT}`) + console.log(`Server is running at http://localhost:${CONFIG.BACKEND_PORT}`) if (CONFIG.GRAPHIQL) { // biome-ignore lint/suspicious/noConsole: no need for logging the start message - console.log(`GraphIQL available at http://localhost:${CONFIG.PORT}`) + console.log(`GraphIQL available at http://localhost:${CONFIG.BACKEND_PORT}`) } }) await startValidateCommunities(Number(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER)) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 059822ea4..a0e449ac2 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -12,7 +12,7 @@ EMAIL_PASSWORD=1234 EMAIL_SMTP_HOST=smtp.lustig.de EMAIL_SMTP_PORT=587 -PORT=4000 +BACKEND_PORT=4000 # if set to true allow sending gradidos to another communities FEDERATION_XCOM_SENDCOINS_ENABLED=false @@ -24,6 +24,14 @@ EMAIL_CODE_VALID_TIME=1440 # also used for password reset code EMAIL_CODE_REQUEST_TIME=10 +# Need to adjust by updates +# config versions +DATABASE_CONFIG_VERSION=v1.2022-03-18 +BACKEND_CONFIG_VERSION=v23.2024-04-04 +FRONTEND_CONFIG_VERSION=v6.2024-02-27 +ADMIN_CONFIG_VERSION=v2.2024-01-04 +FEDERATION_CONFIG_VERSION=v2.2023-08-24 +FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17 FEDERATION_DHT_TOPIC=GRADIDO_HUB # Need adjustments for test system diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 963d0169b..92819f579 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -21,5 +21,5 @@ GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET=$GRADIDO_BLOCKCHAIN_CRYPTO_APP_SECRET GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY # Route to Backend -PORT=$PORT +BACKEND_PORT=$BACKEND_PORT JWT_SECRET=$JWT_SECRET \ No newline at end of file diff --git a/dlt-connector/src/client/backend/BackendClient.ts b/dlt-connector/src/client/backend/BackendClient.ts index 7f779fd73..ce9660e36 100644 --- a/dlt-connector/src/client/backend/BackendClient.ts +++ b/dlt-connector/src/client/backend/BackendClient.ts @@ -30,7 +30,7 @@ export class BackendClient { */ private constructor() { this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.BackendClient`) - this.urlValue = `http://localhost:${CONFIG.PORT}` + this.urlValue = `http://localhost:${CONFIG.BACKEND_PORT}` this.logger.addContext('url', this.urlValue) this.client = new GraphQLClient(this.urlValue, { diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 645f07470..9490e8a00 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -90,7 +90,7 @@ export const configSchema = v.object({ v.string('The home folder for the gradido dlt node server'), path.join(__dirname, '..', '..', 'gradido_node'), ), - PORT: v.optional( + BACKEND_PORT: v.optional( v.pipe( v.string('A valid port on which the backend server is running'), v.transform((input: string) => Number(input)), diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 3d68512ce..3898f9991 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -43,6 +43,26 @@ services: # bind the local folder to the docker to allow live reload - .:/app + ######################################################## + # INSPECTOR ############################################ + ######################################################## + inspector: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/inspector:local-development + build: + target: development + networks: + - external-net + - internal-net + environment: + - NODE_ENV=development + volumes: + # This makes sure the docker container has its own node modules. + # Therefore it is possible to have a different node version on the host machine + - node_modules_inspector:/app/node_modules + # bind the local folder to the docker to allow live reload + - .:/app + ######################################################## # BACKEND ############################################## ######################################################## diff --git a/docker-compose.yml b/docker-compose.yml index aeaac0c60..d2d88cc9c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,6 +61,30 @@ services: volumes: - ./logs/nginx/admin:/var/log/nginx + ######################################################## + # INSPECTOR ########################################### + ######################################################## + inspector: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/inspector:local-production + build: + context: ./inspector + dockerfile: Dockerfile + target: production + networks: + - internal-net + ports: + - ${INSPECTOR_MODULE_PORT:-3100}:3100 + environment: + - NODE_ENV=production + - BUILD_COMMIT=${BUILD_COMMIT} + - BUILD_COMMIT_SHORT=${BUILD_COMMIT_SHORT} + - BUILD_VERSION=${BUILD_VERSION} + # - DEBUG=true + volumes: + - ./logs/nginx/inspector:/var/log/nginx + + ######################################################### ## MARIADB ############################################## ######################################################### @@ -97,7 +121,7 @@ services: environment: # Envs used in Dockerfile # - DOCKER_WORKDIR="/app" - # - PORT=4000 + - BACKEND_PORT=4000 - BUILD_DATE - BUILD_VERSION - BUILD_COMMIT @@ -132,7 +156,6 @@ services: environment: # Envs used in Dockerfile # - DOCKER_WORKDIR="/app" - # - PORT=5000 - BUILD_DATE - BUILD_VERSION - BUILD_COMMIT @@ -167,7 +190,8 @@ services: environment: # Envs used in Dockerfile # - DOCKER_WORKDIR="/app" - - PORT=6010 + - DLT_CONNECTOR_PORT=6010 + - BACKEND_PORT=4000 - BUILD_DATE - BUILD_VERSION - BUILD_COMMIT From f54097e6baffae0ceb4e545742fc7afcf5fbe6aa Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 30 Oct 2025 14:44:47 +0100 Subject: [PATCH 085/226] structure migration --- dlt-connector/.env.dist | 10 +- dlt-connector/.env.template | 10 +- dlt-connector/bun.lock | 248 +++++++++++------- dlt-connector/src/config/schema.ts | 41 +++ .../src/data/KeyPairIdentifier.logic.ts | 8 +- .../resolveKeyPair/ResolveKeyPair.context.ts | 2 +- .../RegisterAddressTransaction.role.test.ts | 4 +- .../db-v2.7.0_to_blockchain-v3.6/Context.ts | 53 ++++ .../OrderedContainer.ts | 58 ++++ .../blockchain.ts | 98 +++++++ .../db-v2.7.0_to_blockchain-v3.6/bootstrap.ts | 49 ++++ .../db-v2.7.0_to_blockchain-v3.6/convert.ts | 86 ++++++ .../db-v2.7.0_to_blockchain-v3.6/database.ts | 176 +++++++++++++ .../db-v2.7.0_to_blockchain-v3.6/index.ts | 171 ++++++++++++ .../db-v2.7.0_to_blockchain-v3.6/keyPair.ts | 56 ++++ .../src/schemas/typeConverter.schema.ts | 12 + 16 files changed, 973 insertions(+), 109 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 165ca7bd0..fe90a30ef 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -22,4 +22,12 @@ GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=a51ef8ac7ef1abf162fb7a65261acd7a # Route to Backend PORT=4000 -JWT_SECRET=secret123 \ No newline at end of file +JWT_SECRET=secret123 + + +# Database +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD= +MYSQL_DATABASE=gradido_community \ No newline at end of file diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 92819f579..18dad36ee 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -22,4 +22,12 @@ GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY # Route to Backend BACKEND_PORT=$BACKEND_PORT -JWT_SECRET=$JWT_SECRET \ No newline at end of file +JWT_SECRET=$JWT_SECRET + + +# Database +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=$DB_USER +MYSQL_PASSWORD=$DB_PASSWORD +MYSQL_DATABASE=gradido_community \ No newline at end of file diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 46e566b54..21caa0f07 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -31,11 +31,11 @@ "packages": { "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="], + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], - "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], - "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], @@ -49,13 +49,13 @@ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], @@ -91,11 +91,11 @@ "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], + "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], @@ -155,15 +155,15 @@ "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], - "@grpc/grpc-js": ["@grpc/grpc-js@1.13.4", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg=="], + "@grpc/grpc-js": ["@grpc/grpc-js@1.12.6", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q=="], "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], - "@hashgraph/cryptography": ["@hashgraph/cryptography@1.9.0", "", { "dependencies": { "@noble/curves": "^1.8.1", "asn1js": "^3.0.6", "bignumber.js": "^9.1.1", "bn.js": "^5.2.1", "buffer": "^6.0.3", "crypto-js": "^4.2.0", "forge-light": "1.1.4", "js-base64": "^3.7.7", "react-native-get-random-values": "^1.11.0", "spark-md5": "^3.0.2", "tweetnacl": "^1.0.3", "utf8": "^3.0.0" } }, "sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg=="], + "@hashgraph/cryptography": ["@hashgraph/cryptography@1.13.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-bttkU9cnbA2NgmE41V4IDYZ5IYMY9HtVTnlvg3fdj8m83+7T4KgTBPPSkqwFCgSeW2x/6MV2GDzvaj4Lx4IYfw=="], - "@hashgraph/proto": ["@hashgraph/proto@2.22.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "7.2.5" } }, "sha512-+h2qqk+KwpV+rr1AN4ip1Gel3X4v0DvFO9WH7o0ZR3gQX9pfzurptKGs30DlBnH21xPqDH61v90bZvVknE27NA=="], + "@hashgraph/proto": ["@hashgraph/proto@2.24.0", "", { "dependencies": { "long": "5.3.1" }, "peerDependencies": { "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "debug": "4.4.1", "protobufjs": "7.5.4", "strip-ansi": "7.1.2" } }, "sha512-S1eE0CoQ17s40JuzKaKpMze8h0JoN13za5arCp3xaqbWVT4UEFq/O/zJud9cpZ31uYwpPe8gH65TPZ3pKd9ZWQ=="], - "@hashgraph/sdk": ["@hashgraph/sdk@2.72.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.22.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-w35M77OAkJutENG4CldUGzfT+qubDjEYCQR5Ran75uHB+SLeCodR87AXWJ3ocr5vPaZ7lsflBXEYZLhgCi1G2g=="], + "@hashgraph/sdk": ["@hashgraph/sdk@2.75.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.13.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-Nkv57So2RbNlKxog1nsyqHgorgrStr3yzx0ZWse4R6yg1TztafiqA2+9m3YlmH3eNMr7vmghgtGqPkRflfVhZg=="], "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], @@ -193,13 +193,13 @@ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], - "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="], - "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="], "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], @@ -221,23 +221,25 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@react-native/assets-registry": ["@react-native/assets-registry@0.81.1", "", {}, "sha512-o/AeHeoiPW8x9MzxE1RSnKYc+KZMW9b7uaojobEz0G8fKgGD1R8n5CJSOiQ/0yO2fJdC5wFxMMOgy2IKwRrVgw=="], + "@react-native/assets-registry": ["@react-native/assets-registry@0.82.1", "", {}, "sha512-B1SRwpntaAcckiatxbjzylvNK562Ayza05gdJCjDQHTiDafa1OABmyB5LHt7qWDOpNkaluD+w11vHF7pBmTpzQ=="], - "@react-native/codegen": ["@react-native/codegen@0.81.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-8KoUE1j65fF1PPHlAhSeUHmcyqpE+Z7Qv27A89vSZkz3s8eqWSRu2hZtCl0D3nSgS0WW0fyrIsFaRFj7azIiPw=="], + "@react-native/codegen": ["@react-native/codegen@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-ezXTN70ygVm9l2m0i+pAlct0RntoV4afftWMGUIeAWLgaca9qItQ54uOt32I/9dBJvzBibT33luIR/pBG0dQvg=="], - "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.1", "", { "dependencies": { "@react-native/dev-middleware": "0.81.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-FuIpZcjBiiYcVMNx+1JBqTPLs2bUIm6X4F5enYGYcetNE2nfSMUVO8SGUtTkBdbUTfKesXYSYN8wungyro28Ag=="], + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.82.1", "", { "dependencies": { "@react-native/dev-middleware": "0.82.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-H/eMdtOy9nEeX7YVeEG1N2vyCoifw3dr9OV8++xfUElNYV7LtSmJ6AqxZUUfxGJRDFPQvaU/8enmJlM/l11VxQ=="], - "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.1", "", {}, "sha512-dwKv1EqKD+vONN4xsfyTXxn291CNl1LeBpaHhNGWASK1GO4qlyExMs4TtTjN57BnYHikR9PzqPWcUcfzpVRaLg=="], + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.82.1", "", {}, "sha512-a2O6M7/OZ2V9rdavOHyCQ+10z54JX8+B+apYKCQ6a9zoEChGTxUMG2YzzJ8zZJVvYf1ByWSNxv9Se0dca1hO9A=="], - "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-hy3KlxNOfev3O5/IuyZSstixWo7E9FhljxKGHdvVtZVNjQdM+kPMh66mxeJbB2TjdJGAyBT4DjIwBaZnIFOGHQ=="], + "@react-native/debugger-shell": ["@react-native/debugger-shell@0.82.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "fb-dotslash": "0.5.8" } }, "sha512-fdRHAeqqPT93bSrxfX+JHPpCXHApfDUdrXMXhoxlPgSzgXQXJDykIViKhtpu0M6slX6xU/+duq+AtP/qWJRpBw=="], - "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.1", "", {}, "sha512-RpRxs/LbWVM9Zi5jH1qBLgTX746Ei+Ui4vj3FmUCd9EXUSECM5bJpphcsvqjxM5Vfl/o2wDLSqIoFkVP/6Te7g=="], + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.82.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.82.1", "@react-native/debugger-shell": "0.82.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-wuOIzms/Qg5raBV6Ctf2LmgzEOCqdP3p1AYN4zdhMT110c39TVMbunpBaJxm0Kbt2HQ762MQViF9naxk7SBo4w=="], - "@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.1", "", {}, "sha512-w093OkHFfCnJKnkiFizwwjgrjh5ra53BU0ebPM3uBLkIQ6ZMNSCTZhG8ZHIlAYeIGtEinvmnSUi3JySoxuDCAQ=="], + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.82.1", "", {}, "sha512-KkF/2T1NSn6EJ5ALNT/gx0MHlrntFHv8YdooH9OOGl9HQn5NM0ZmQSr86o5utJsGc7ME3R6p3SaQuzlsFDrn8Q=="], - "@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.1", "", {}, "sha512-TsaeZlE8OYFy3PSWc+1VBmAzI2T3kInzqxmwXoGU4w1d4XFkQFg271Ja9GmDi9cqV3CnBfqoF9VPwRxVlc/l5g=="], + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.82.1", "", {}, "sha512-tf70X7pUodslOBdLN37J57JmDPB/yiZcNDzS2m+4bbQzo8fhx3eG9QEBv5n4fmzqfGAgSB4BWRHgDMXmmlDSVA=="], - "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-yG+zcMtyApW1yRwkNFvlXzEg3RIFdItuwr/zEvPCSdjaL+paX4rounpL0YX5kS9MsDIE5FXfcqINXg7L0xuwPg=="], + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.82.1", "", {}, "sha512-CCfTR1uX+Z7zJTdt3DNX9LUXr2zWXsNOyLbwupW2wmRzrxlHRYfmLgTABzRL/cKhh0Ubuwn15o72MQChvCRaHw=="], + + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.82.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-f5zpJg9gzh7JtCbsIwV+4kP3eI0QBuA93JGmwFRd4onQ3DnCjV2J5pYqdWtM95sjSKK1dyik59Gj01lLeKqs1Q=="], "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], @@ -261,7 +263,7 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], + "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="], @@ -271,15 +273,15 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], - "@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="], + "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="], - "@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="], + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/uuid": ["@types/uuid@8.3.4", "", {}, "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="], - "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@types/yargs": ["@types/yargs@17.0.34", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], @@ -295,9 +297,9 @@ "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -327,7 +329,7 @@ "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@29.6.3", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg=="], - "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], + "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.32.0", "", { "dependencies": { "hermes-parser": "0.32.0" } }, "sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg=="], "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], @@ -337,13 +339,15 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.20", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ=="], + + "bignumber.js": ["bignumber.js@9.1.1", "", {}, "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig=="], "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], - "bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="], + "bn.js": ["bn.js@5.1.1", "", {}, "sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], @@ -351,7 +355,7 @@ "brorand": ["brorand@1.1.0", "", {}, "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="], - "browserslist": ["browserslist@4.25.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg=="], + "browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="], "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], @@ -359,19 +363,13 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - "caller-callsite": ["caller-callsite@2.0.0", "", { "dependencies": { "callsites": "^2.0.0" } }, "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ=="], - - "caller-path": ["caller-path@2.0.0", "", { "dependencies": { "caller-callsite": "^2.0.0" } }, "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A=="], - - "callsites": ["callsites@2.0.0", "", {}, "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ=="], - "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001741", "", {}, "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -409,7 +407,7 @@ "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - "cosmiconfig": ["cosmiconfig@5.2.1", "", { "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], @@ -437,7 +435,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.214", "", {}, "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q=="], + "electron-to-chromium": ["electron-to-chromium@1.5.241", "", {}, "sha512-ILMvKX/ZV5WIJzzdtuHg8xquk2y0BOGlFOxBVwTpbiXqWIH0hamG45ddU4R3PQ0gYu+xgo0vdHXHli9sHIGb4w=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -449,8 +447,6 @@ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], - "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], @@ -477,7 +473,7 @@ "execspawn": ["execspawn@1.0.1", "", { "dependencies": { "util-extend": "^1.0.1" } }, "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg=="], - "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], "fast-base64-decode": ["fast-base64-decode@1.0.0", "", {}, "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="], @@ -491,6 +487,8 @@ "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + "fb-dotslash": ["fb-dotslash@0.5.8", "", { "bin": { "dotslash": "bin/dotslash" } }, "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA=="], + "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], @@ -547,11 +545,11 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#f1c4bbc", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-f1c4bbc"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#8a0c7b0", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-8a0c7b0"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], - "graphql-request": ["graphql-request@7.2.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A=="], + "graphql-request": ["graphql-request@7.3.1", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-GdinBsBVYrWzwEvOlzadrV5j8mdOc9ZT8In9QyRIZaxbhkTL08j35yNbPp96jAacYzjeD/hKKy2E2RGI7c7Yug=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], @@ -567,9 +565,11 @@ "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], - "hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="], + "hermes-compiler": ["hermes-compiler@0.0.0", "", {}, "sha512-boVFutx6ME/Km2mB6vvsQcdnazEYYI/jV1pomx1wcFUG/EVqTkr5CU0CW9bKipOA/8Hyu3NYwW3THg2Q1kNCfA=="], - "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="], + "hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + + "hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], "hmac-drbg": ["hmac-drbg@1.0.1", "", { "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg=="], @@ -581,8 +581,6 @@ "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], - "import-fresh": ["import-fresh@2.0.0", "", { "dependencies": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" } }, "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], @@ -593,10 +591,6 @@ "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - - "is-directory": ["is-directory@0.3.1", "", {}, "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw=="], - "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], @@ -633,7 +627,7 @@ "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], - "js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="], + "js-base64": ["js-base64@3.7.4", "", {}, "sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ=="], "js-sha3": ["js-sha3@0.8.0", "", {}, "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="], @@ -645,8 +639,6 @@ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], @@ -665,7 +657,7 @@ "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], - "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + "long": ["long@5.3.1", "", {}, "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -683,33 +675,33 @@ "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], - "metro": ["metro@0.83.1", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.29.1", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-config": "0.83.1", "metro-core": "0.83.1", "metro-file-map": "0.83.1", "metro-resolver": "0.83.1", "metro-runtime": "0.83.1", "metro-source-map": "0.83.1", "metro-symbolicate": "0.83.1", "metro-transform-plugins": "0.83.1", "metro-transform-worker": "0.83.1", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-UGKepmTxoGD4HkQV8YWvpvwef7fUujNtTgG4Ygf7m/M0qjvb9VuDmAsEU+UdriRX7F61pnVK/opz89hjKlYTXA=="], + "metro": ["metro@0.83.3", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.32.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-config": "0.83.3", "metro-core": "0.83.3", "metro-file-map": "0.83.3", "metro-resolver": "0.83.3", "metro-runtime": "0.83.3", "metro-source-map": "0.83.3", "metro-symbolicate": "0.83.3", "metro-transform-plugins": "0.83.3", "metro-transform-worker": "0.83.3", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q=="], - "metro-babel-transformer": ["metro-babel-transformer@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.29.1", "nullthrows": "^1.1.1" } }, "sha512-r3xAD3964E8dwDBaZNSO2aIIvWXjIK80uO2xo0/pi3WI8XWT9h5SCjtGWtMtE5PRWw+t20TN0q1WMRsjvhC1rQ=="], + "metro-babel-transformer": ["metro-babel-transformer@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" } }, "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g=="], - "metro-cache": ["metro-cache@0.83.1", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.1" } }, "sha512-7N/Ad1PHa1YMWDNiyynTPq34Op2qIE68NWryGEQ4TSE3Zy6a8GpsYnEEZE4Qi6aHgsE+yZHKkRczeBgxhnFIxQ=="], + "metro-cache": ["metro-cache@0.83.3", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.3" } }, "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q=="], - "metro-cache-key": ["metro-cache-key@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ZUs+GD5CNeDLxx5UUWmfg26IL+Dnbryd+TLqTlZnDEgehkIa11kUSvgF92OFfJhONeXzV4rZDRGNXoo6JT+8Gg=="], + "metro-cache-key": ["metro-cache-key@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw=="], - "metro-config": ["metro-config@0.83.1", "", { "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.1", "metro-cache": "0.83.1", "metro-core": "0.83.1", "metro-runtime": "0.83.1" } }, "sha512-HJhpZx3wyOkux/jeF1o7akFJzZFdbn6Zf7UQqWrvp7gqFqNulQ8Mju09raBgPmmSxKDl4LbbNeigkX0/nKY1QA=="], + "metro-config": ["metro-config@0.83.3", "", { "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.3", "metro-cache": "0.83.3", "metro-core": "0.83.3", "metro-runtime": "0.83.3", "yaml": "^2.6.1" } }, "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA=="], - "metro-core": ["metro-core@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.1" } }, "sha512-uVL1eAJcMFd2o2Q7dsbpg8COaxjZBBGaXqO2OHnivpCdfanraVL8dPmY6It9ZeqWLOihUKZ2yHW4b6soVCzH/Q=="], + "metro-core": ["metro-core@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.3" } }, "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw=="], - "metro-file-map": ["metro-file-map@0.83.1", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-Yu429lnexKl44PttKw3nhqgmpBR+6UQ/tRaYcxPeEShtcza9DWakCn7cjqDTQZtWR2A8xSNv139izJMyQ4CG+w=="], + "metro-file-map": ["metro-file-map@0.83.3", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA=="], - "metro-minify-terser": ["metro-minify-terser@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-kmooOxXLvKVxkh80IVSYO4weBdJDhCpg5NSPkjzzAnPJP43u6+usGXobkTWxxrAlq900bhzqKek4pBsUchlX6A=="], + "metro-minify-terser": ["metro-minify-terser@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ=="], - "metro-resolver": ["metro-resolver@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-t8j46kiILAqqFS5RNa+xpQyVjULxRxlvMidqUswPEk5nQVNdlJslqizDm/Et3v/JKwOtQGkYAQCHxP1zGStR/g=="], + "metro-resolver": ["metro-resolver@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ=="], - "metro-runtime": ["metro-runtime@0.83.1", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-3Ag8ZS4IwafL/JUKlaeM6/CbkooY+WcVeqdNlBG0m4S0Qz0om3rdFdy1y6fYBpl6AwXJwWeMuXrvZdMuByTcRA=="], + "metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], - "metro-source-map": ["metro-source-map@0.83.1", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.1", "nullthrows": "^1.1.1", "ob1": "0.83.1", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-De7Vbeo96fFZ2cqmI0fWwVJbtHIwPZv++LYlWSwzTiCzxBDJORncN0LcT48Vi2UlQLzXJg+/CuTAcy7NBVh69A=="], + "metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], - "metro-symbolicate": ["metro-symbolicate@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.1", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-wPxYkONlq/Sv8Ji7vHEx5OzFouXAMQJjpcPW41ySKMLP/Ir18SsiJK2h4YkdKpYrTS1+0xf8oqF6nxCsT3uWtg=="], + "metro-symbolicate": ["metro-symbolicate@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw=="], - "metro-transform-plugins": ["metro-transform-plugins@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-1Y+I8oozXwhuS0qwC+ezaHXBf0jXW4oeYn4X39XWbZt9X2HfjodqY9bH9r6RUTsoiK7S4j8Ni2C91bUC+sktJQ=="], + "metro-transform-plugins": ["metro-transform-plugins@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A=="], - "metro-transform-worker": ["metro-transform-worker@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-minify-terser": "0.83.1", "metro-source-map": "0.83.1", "metro-transform-plugins": "0.83.1", "nullthrows": "^1.1.1" } }, "sha512-owCrhPyUxdLgXEEEAL2b14GWTPZ2zYuab1VQXcfEy0sJE71iciD7fuMcrngoufh7e7UHDZ56q4ktXg8wgiYA1Q=="], + "metro-transform-worker": ["metro-transform-worker@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.3", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-minify-terser": "0.83.3", "metro-source-map": "0.83.3", "metro-transform-plugins": "0.83.3", "nullthrows": "^1.1.1" } }, "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], @@ -741,17 +733,17 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "node-abi": ["node-abi@3.77.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ=="], + "node-abi": ["node-abi@3.78.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], - "node-api-headers": ["node-api-headers@1.5.0", "", {}, "sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ=="], + "node-api-headers": ["node-api-headers@1.6.0", "", {}, "sha512-81T99+mWLZnxX0LlZPYuafyFlxVVaWKQ0BDAbSrOqLO+v+gzCzu0GTAVNeVK8lucqjqo9L/1UcK9cpkem8Py4Q=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], - "node-releases": ["node-releases@2.0.20", "", {}, "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA=="], + "node-releases": ["node-releases@2.0.26", "", {}, "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -765,7 +757,7 @@ "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], - "ob1": ["ob1@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ngwqewtdUzFyycomdbdIhFLjePPSOt1awKMUXQ0L7iLHgWEPF3DsCerblzjzfAUHaXuvE9ccJymWQ/4PNNqvnQ=="], + "ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], @@ -783,8 +775,6 @@ "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], - "parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -797,11 +787,11 @@ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pino": ["pino@9.9.4", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg=="], + "pino": ["pino@9.6.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], - "pino-pretty": ["pino-pretty@13.1.1", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^5.0.2" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA=="], + "pino-pretty": ["pino-pretty@13.0.0", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^2.4.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^3.1.1" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA=="], "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], @@ -811,11 +801,11 @@ "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], - "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + "process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="], "promise": ["promise@8.3.0", "", { "dependencies": { "asap": "~2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="], - "protobufjs": ["protobufjs@7.2.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A=="], + "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], @@ -823,7 +813,7 @@ "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], - "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], + "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="], "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], @@ -833,13 +823,13 @@ "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], "react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="], "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "react-native": ["react-native@0.81.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.1", "@react-native/codegen": "0.81.1", "@react-native/community-cli-plugin": "0.81.1", "@react-native/gradle-plugin": "0.81.1", "@react-native/js-polyfills": "0.81.1", "@react-native/normalize-colors": "0.81.1", "@react-native/virtualized-lists": "0.81.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-k2QJzWc/CUOwaakmD1SXa4uJaLcwB2g2V9BauNIjgtXYYAeyFjx9jlNz/+wAEcHLg9bH5mgMdeAwzvXqjjh9Hg=="], + "react-native": ["react-native@0.82.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.82.1", "@react-native/codegen": "0.82.1", "@react-native/community-cli-plugin": "0.82.1", "@react-native/gradle-plugin": "0.82.1", "@react-native/js-polyfills": "0.82.1", "@react-native/normalize-colors": "0.82.1", "@react-native/virtualized-lists": "0.82.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "hermes-compiler": "0.0.0", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "^19.1.1" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-tFAqcU7Z4g49xf/KnyCEzI4nRTu1Opcx05Ov2helr8ZTg1z7AJR/3sr2rZ+AAVlAs2IXk+B0WOxXGmdD3+4czA=="], "react-native-get-random-values": ["react-native-get-random-values@1.11.0", "", { "dependencies": { "fast-base64-decode": "^1.0.0" }, "peerDependencies": { "react-native": ">=0.56" } }, "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ=="], @@ -855,7 +845,7 @@ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "rfc4648": ["rfc4648@1.5.4", "", {}, "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg=="], + "rfc4648": ["rfc4648@1.5.3", "", {}, "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ=="], "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], @@ -867,9 +857,9 @@ "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], - "secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="], + "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], - "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], @@ -881,6 +871,10 @@ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], @@ -913,9 +907,9 @@ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], @@ -923,7 +917,7 @@ "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - "tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], @@ -951,17 +945,17 @@ "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], - "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], - "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], @@ -999,27 +993,53 @@ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/traverse/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@babel/traverse--for-generate-function-map/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@ethersproject/bignumber/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@ethersproject/signing-key/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@hashgraph/cryptography/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@hashgraph/cryptography/js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], + "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], "@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + "@react-native/community-cli-plugin/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@react-native/dev-middleware/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@tokenizer/inflate/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "cmake-js/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "cmake-js/fs-extra": ["fs-extra@11.3.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g=="], + "cmake-js/axios": ["axios@1.13.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-zt40Pz4zcRXra9CVV31KeyofwiNvAbJ5B6YPz9pMJ+yOSLikvPT4Yi5LjfgjRa9CawVYBaD1JQzIVcIvBejKeA=="], + + "cmake-js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "cmake-js/fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="], "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -1031,9 +1051,11 @@ "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "gauge/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], - "import-fresh/resolve-from": ["resolve-from@3.0.0", "", {}, "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="], + "https-proxy-agent/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -1041,22 +1063,34 @@ "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "jsonrpc-ts-client/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "log4js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "metro/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "metro-file-map/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "npm-path/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], "npm-which/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "react-native/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -1071,10 +1105,18 @@ "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + "streamroller/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "cmake-js/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -1083,8 +1125,14 @@ "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "gauge/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], } } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 9490e8a00..9131a3132 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -99,4 +99,45 @@ export const configSchema = v.object({ ), '4000', ), + MYSQL_HOST: v.optional( + v.string('The host of the database'), + 'localhost', + ), + MYSQL_PORT: v.optional( + v.pipe( + v.string('The port of the database'), + v.transform((input: string) => Number.parseInt(input)), + v.minValue(1), + v.maxValue(65535), + ), + '3306', + ), + MYSQL_USER: v.optional( + v.pipe( + v.string('The user name of the database'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === 'root') { + return false + } + return true + }, "Shouldn't use default root user in production"), + ), + 'root', + ), + MYSQL_PASSWORD: v.optional( + v.pipe( + v.string('The password of the database'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === '') { + return false + } + return true + }, "Shouldn't use empty password in production"), + ), + '', + ), + MYSQL_DATABASE: v.optional( + v.string('The name of the database'), + 'gradido_community', + ), }) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 7ae40ea99..61f4d3cfb 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -79,10 +79,10 @@ export class KeyPairIdentifierLogic { return this.getCommunityTopicId() } getCommunityUserKey(): string { - return this.deriveCommunityUserHash() + return this.deriveCommunityUserHash(0) } getCommunityUserAccountKey(): string { - return this.deriveCommunityUserHash() + this.getAccountNr().toString() + return this.deriveCommunityUserHash(this.getAccountNr()) } getKey(): string { @@ -100,14 +100,14 @@ export class KeyPairIdentifierLogic { } } - private deriveCommunityUserHash(): string { + private deriveCommunityUserHash(accountNr: number): string { if (!this.identifier.account) { throw new InvalidCallError( 'Invalid call: getCommunityUserKey or getCommunityUserAccountKey() on non-user/non-account identifier', ) } const resultString = - this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + accountNr.toString() return new MemoryBlock(resultString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 406463c4c..21187602b 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -32,7 +32,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' */ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { const cache = KeyPairCacheManager.getInstance() - + return await cache.getKeyPair( input.getKey(), // function is called from cache manager, if key isn't currently cached diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index ef896e1e8..7bb6e1140 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'bun:test' -import { InteractionToJson, InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' +import { InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' import * as v from 'valibot' import { transactionSchema } from '../../schemas/transaction.schema' import { hieroIdSchema } from '../../schemas/typeGuard.schema' @@ -31,7 +31,7 @@ describe('RegisterAddressTransaction.role', () => { const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() const gradidoTransaction = builder.build() expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() - const json = JSON.parse(new InteractionToJson(gradidoTransaction).run()) + const json = JSON.parse(gradidoTransaction.toJson(true)) expect(json.bodyBytes.json.registerAddress.nameHash).toBe( 'bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08', ) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts new file mode 100644 index 000000000..b60a08b08 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts @@ -0,0 +1,53 @@ +import { SQL } from 'bun' +import { InMemoryBlockchain } from 'gradido-blockchain-js' +import { Logger } from 'log4js' + +import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' + +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { loadConfig } from '../../bootstrap/init' +import { CONFIG } from '../../config' + + +export type CommunityContext = { + communityId: string + blockchain: InMemoryBlockchain + topicId: HieroId +} + +export class Context { + public logger: Logger + public db: SQL + public communities: Map + public cache: KeyPairCacheManager + + constructor(logger: Logger, db: SQL, cache: KeyPairCacheManager) { + this.logger = logger + this.db = db + this.cache = cache + this.communities = new Map() + } + + static create(): Context { + return new Context( + loadConfig(), + new SQL({ + adapter: 'mysql', + hostname: CONFIG.MYSQL_HOST, + username: CONFIG.MYSQL_USER, + password: CONFIG.MYSQL_PASSWORD, + database: CONFIG.MYSQL_DATABASE, + port: CONFIG.MYSQL_PORT + }), + KeyPairCacheManager.getInstance() + ) + } + + getCommunityContextByUuid(communityUuid: Uuidv4): CommunityContext { + const community = this.communities.get(communityUuid) + if (!community) { + throw new Error(`Community not found for communityUuid ${communityUuid}`) + } + return community + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts new file mode 100644 index 000000000..90dcc0e74 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts @@ -0,0 +1,58 @@ + +export type Loader = (context: ContextType, offset: number, count: number) => Promise + +export interface Orderable { + getDate(): Date + // return count of new loaded items + ensureFilled(context: ContextType, batchSize: number): Promise + pushToBlockchain(context: ContextType): Promise + isEmpty(): boolean +} + +export class OrderedContainer implements Orderable { + private items: T[] = [] + private offset = 0 + + constructor( + private readonly loader: Loader, + private readonly getDateHandler: (item: T) => Date, + private readonly pushToBlockchainHandler: (context: ContextType, item: T) => Promise + ) {} + + + async ensureFilled(context: ContextType, batchSize: number): Promise { + if (this.items.length === 0) { + this.items = await this.loader(context, this.offset, batchSize) + this.offset += this.items.length + return this.items.length + } + return 0 + } + + async pushToBlockchain(context: ContextType): Promise { + return this.pushToBlockchainHandler(context, this.shift()) + } + + peek(): T { + if (this.isEmpty()) { + throw new Error(`[peek] No items, please call this only if isEmpty returns false`) + } + return this.items[0] + } + + shift(): T { + const item = this.items.shift() + if (!item) { + throw new Error(`[shift] No items, shift return undefined`) + } + return item + } + + getDate(): Date { + return this.getDateHandler(this.peek()) + } + + isEmpty(): boolean { + return this.items.length === 0 + } +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts new file mode 100644 index 000000000..22fa9b400 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts @@ -0,0 +1,98 @@ +import { sql, SQL } from 'bun' +import { + InMemoryBlockchain, + InMemoryBlockchainProvider, + GradidoTransactionBuilder, + KeyPairEd25519, + MemoryBlock, + Timestamp, + HieroTransactionId, + HieroAccountId, + InteractionSerialize, + loadCryptoKeys, + Filter, + SearchDirection_ASC +} from 'gradido-blockchain-js' +import { Logger, getLogger } from 'log4js' +import { CONFIG } from '../../config' +import { amountSchema, HieroId, hieroIdSchema, memoSchema, uuidv4Schema, Uuidv4, gradidoAmountSchema } from '../../schemas/typeGuard.schema' +import { dateSchema } from '../../schemas/typeConverter.schema' +import * as v from 'valibot' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { AccountType } from '../../data/AccountType.enum' +import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' +import { loadConfig } from '../../bootstrap/init' +import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb } from './database' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { Community, Transaction } from '../../schemas/transaction.schema' +import { communityDbToCommunity, userDbToTransaction } from './convert' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) +export const defaultHieroAccount = new HieroAccountId(0, 0, 2) + +function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { + const transaction = builder.build() + const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) + const interactionSerialize = new InteractionSerialize(transactionId) + return blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) +} + +export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { + const communityRootTransactionRole = new CommunityRootTransactionRole(community) + if(addToBlockchain(await communityRootTransactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(community.creationDate))) { + logger.info(`Community Root Transaction added`) + } else { + throw new Error(`Community Root Transaction not added`) + } +} + +export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { + const registerAddressRole = new RegisterAddressTransactionRole(transaction) + if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { + logger.info(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) + } +} +/* + + +export async function addTransaction(blockchain: InMemoryBlockchain, transactionDb: TransactionDb): Promise { + + let transactionRole: AbstractTransactionRole + switch (transactionDb.typeId) { + case TransactionTypeId.CREATION: + transactionRole = new CreationTransactionRole({ + user: { + communityTopicId: transactionDb.user.communityTopicId, + account: { + userUuid: transactionDb.user.gradidoId, + accountNr: 0, + }, + }, + linkedUser: { + communityTopicId: transactionDb.linkedUser.communityTopicId, + account: { + userUuid: transactionDb.linkedUser.gradidoId, + accountNr: 0, + }, + }, + amount: v.parse(gradidoAmountSchema, transactionDb.amount), + memo: v.parse(memoSchema, transactionDb.memo), + createdAt: transactionDb.creationDate, + targetDate: transactionDb.balanceDate, + type: getInputTransactionTypeFromTypeId(transactionDb.typeId), + }) + if(addToBlockchain(await transactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transactionDb.creationDate))) { + logger.info(`Transaction added for user ${transactionDb.user.gradidoId}`) + } else { + throw new Error(`Transaction not added for user ${transactionDb.user.gradidoId}`) + } +} +*/ \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts new file mode 100644 index 000000000..325347369 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts @@ -0,0 +1,49 @@ +import { Context } from './Context' +import { CommunityContext } from './Context' +import { loadCommunities } from './database' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' +import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' +import { generateKeyPairCommunity } from './keyPair' +import { communityDbToCommunity } from './convert' +import { addCommunityRootTransaction } from './blockchain' + +export async function bootstrap(): Promise { + const context = Context.create() + context.communities = await bootstrapCommunities(context) + return context +} + +async function bootstrapCommunities(context: Context): Promise> { + const communities = new Map() + const communitiesDb = await loadCommunities(context.db) + const topicIds = new Set() + + for (const communityDb of communitiesDb) { + const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain(communityDb.uniqueAlias) + if (!blockchain) { + throw new Error(`Couldn't create Blockchain for community ${communityDb.communityUuid}`) + } + context.logger.info(`Blockchain for community '${communityDb.uniqueAlias}' created`) + // make sure topic id is unique + let topicId: HieroId + do { + topicId = v.parse(hieroIdSchema, '0.0.' + Math.floor(Math.random() * 10000)) + } while(topicIds.has(topicId)) + topicIds.add(topicId) + + communities.set(communityDb.communityUuid, { + communityId: communityDb.uniqueAlias, + blockchain, + topicId + }) + + generateKeyPairCommunity(communityDb, context.cache, topicId) + // create community root transaction 1 minute before first user + const creationDate = new Date(new Date(communityDb.userMinCreatedAt).getTime() - 1000 * 60) + // community from db to community format the dlt connector normally uses + const community = communityDbToCommunity(topicId, communityDb, creationDate) + await addCommunityRootTransaction(blockchain, community) + } + return communities +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts new file mode 100644 index 000000000..f182664bc --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts @@ -0,0 +1,86 @@ +import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb } from './database' +import { Community, communitySchema, transactionSchema, Transaction, TransactionInput } from '../../schemas/transaction.schema' +import { AccountType } from '../../data/AccountType.enum' +import { gradidoAmountSchema, HieroId, memoSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' + +export function getInputTransactionTypeFromTypeId(typeId: TransactionTypeId): InputTransactionType { + switch (typeId) { + case TransactionTypeId.CREATION: + return InputTransactionType.GRADIDO_CREATION + case TransactionTypeId.SEND: + return InputTransactionType.GRADIDO_TRANSFER + case TransactionTypeId.RECEIVE: + throw new Error('not used') + default: + throw new Error('not implemented') + } +} + +export function communityDbToCommunity(topicId: HieroId, communityDb: CommunityDb, creationDate: Date): Community { + return v.parse(communitySchema, { + hieroTopicId: topicId, + uuid: communityDb.communityUuid, + foreign: communityDb.foreign, + creationDate, + }) +} + +export function userDbToTransaction(userDb: CreatedUserDb, communityTopicId: HieroId): Transaction { + return v.parse(transactionSchema, { + user: { + communityTopicId: communityTopicId, + account: { userUuid: userDb.gradidoId }, + }, + type: InputTransactionType.REGISTER_ADDRESS, + accountType: AccountType.COMMUNITY_HUMAN, + createdAt: userDb.createdAt, + }) +} + +export function transactionDbToTransaction(transactionDb: TransactionDb, communityTopicId: HieroId, recipientCommunityTopicId: HieroId): Transaction { + if ( + transactionDb.typeId !== TransactionTypeId.CREATION + && transactionDb.typeId !== TransactionTypeId.SEND + && transactionDb.typeId !== TransactionTypeId.RECEIVE) { + throw new Error('not implemented') + } + const user = { + communityTopicId: communityTopicId, + account: { userUuid: transactionDb.user.gradidoId }, + } + const linkedUser = { + communityTopicId: recipientCommunityTopicId, + account: { userUuid: transactionDb.linkedUser.gradidoId }, + } + const transaction: TransactionInput = { + user, + linkedUser, + amount: v.parse(gradidoAmountSchema, transactionDb.amount), + memo: v.parse(memoSchema, transactionDb.memo), + type: InputTransactionType.GRADIDO_TRANSFER, + createdAt: transactionDb.balanceDate, + } + if (transactionDb.typeId === TransactionTypeId.CREATION) { + if (!transactionDb.creationDate) { + throw new Error('contribution transaction without creation date') + } + transaction.targetDate = transactionDb.creationDate + transaction.type = InputTransactionType.GRADIDO_CREATION + } else if (transactionDb.typeId === TransactionTypeId.RECEIVE) { + transaction.user = linkedUser + transaction.linkedUser = user + } + if (transactionDb.transactionLinkCode) { + if (transactionDb.typeId !== TransactionTypeId.RECEIVE) { + throw new Error('linked transaction which isn\'t receive, send will taken care of on link creation') + } + transaction.user = { + communityTopicId: recipientCommunityTopicId, + seed: transactionDb.transactionLinkCode, + } + transaction.type = InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER + } + return v.parse(transactionSchema, transaction) +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts new file mode 100644 index 000000000..71561e33d --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts @@ -0,0 +1,176 @@ +import { SQL } from 'bun' +import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema } from '../../schemas/typeGuard.schema' +import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' +import * as v from 'valibot' +import { GradidoUnit } from 'gradido-blockchain-js' + +export const createdUserDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, + createdAt: dateSchema, +}) + +export const userDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, +}) + +export enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} + +export const transactionDbSchema = v.object({ + typeId: v.enum(TransactionTypeId), + amount: amountSchema, + balanceDate: dateSchema, + memo: memoSchema, + creationDate: v.nullish(dateSchema), + user: userDbSchema, + linkedUser: userDbSchema, + transactionLinkCode: v.nullish(identifierSeedSchema), +}) + +export const transactionLinkDbSchema = v.object({ + userUuid: uuidv4Schema, + code: identifierSeedSchema, + amount: amountSchema, + memo: memoSchema, + createdAt: dateSchema, + validUntil: dateSchema, +}) + +export const communityDbSchema = v.object({ + foreign: booleanSchema, + communityUuid: uuidv4Schema, + name: v.string(), + creationDate: dateSchema, + userMinCreatedAt: dateSchema, + uniqueAlias: v.string(), +}) + +export type TransactionDb = v.InferOutput +export type UserDb = v.InferOutput +export type CreatedUserDb = v.InferOutput +export type TransactionLinkDb = v.InferOutput +export type CommunityDb = v.InferOutput + +// queries +export async function loadCommunities(db: SQL): Promise { + const result = await db` + SELECT c.foreign, c.community_uuid as communityUuid, c.name as name, c.creation_date as creationDate, MIN(u.created_at) as userMinCreatedAt + FROM communities c + LEFT JOIN users u ON c.community_uuid = u.community_uuid + WHERE c.community_uuid IS NOT NULL + GROUP BY c.community_uuid + ` + const communityNames = new Set() + return result.map((row: any) => { + let alias = row.name + if (communityNames.has(row.name)) { + alias = row.community_uuid + } else { + communityNames.add(row.name) + } + return v.parse(communityDbSchema, { + ...row, + uniqueAlias: alias, + }) + }) +} + +export async function loadUsers(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT id, gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users + ORDER by created_at ASC + LIMIT ${offset}, ${count} + ` + const totalCount = await db` + SELECT COUNT(*) as count FROM users + ` + console.log(`Loaded ${result.length} users, total ${totalCount[0].count} with offset ${offset} and count ${count}`) + return result.map((row: any) => { + return v.parse(createdUserDbSchema, row) + }) +} + +export async function loadTransactions(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT type_id, amount, balance_date, memo, creation_date, + u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, + lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, + tl.code as transaction_link_code + FROM transactions + LEFT JOIN users u ON transactions.user_id = u.id + LEFT JOIN users lu ON transactions.linked_user_id = lu.id + LEFT JOIN transaction_links tl ON transactions.transaction_link_id = tl.id + ORDER by balance_date ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + let amount = GradidoUnit.fromString(row.amount) + if (row.type_id === TransactionTypeId.SEND) { + amount = amount.mul(new GradidoUnit(-1)) + } + return v.parse(transactionDbSchema, { + typeId: row.type_id, + amount, + balanceDate: new Date(row.balance_date), + memo: row.memo, + creationDate: new Date(row.creation_date), + transactionLinkCode: row.transaction_link_code, + user: { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + }, + linkedUser: { + gradidoId: row.linked_user_gradido_id, + communityUuid: row.linked_user_community_uuid + } + }) + }) +} + +export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT u.gradido_id as userUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil + FROM transaction_links tl + LEFT JOIN users u ON tl.userId = u.id + ORDER by createdAt ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + return v.parse(transactionLinkDbSchema, row) + }) +} + +export async function loadDeletedTransactionLinks(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT u.gradido_id as user_gradido_id, u.community_uuid as user_community_uuid, + tl.code, tl.amount, tl.memo, tl.deletedAt + FROM transaction_links tl + LEFT JOIN users u ON tl.userId = u.id + WHERE deletedAt IS NOT NULL + ORDER by deletedAt ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + const user = { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + } + return v.parse(transactionDbSchema, { + typeId: TransactionTypeId.RECEIVE, + amount: row.amount, + balanceDate: new Date(row.deletedAt), + memo: row.memo, + transactionLinkCode: row.code, + user, + linkedUser: user + }) + }) +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts new file mode 100644 index 000000000..201526fbb --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts @@ -0,0 +1,171 @@ +import { + InMemoryBlockchain, + Filter, + SearchDirection_ASC, + HieroTransactionId, + Timestamp, + InteractionSerialize +} from 'gradido-blockchain-js' +import { Logger } from 'log4js' + +import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' +import { addRegisterAddressTransaction, defaultHieroAccount } from './blockchain' +import { generateKeyPairUserAccount } from './keyPair' +import { transactionDbToTransaction, userDbToTransaction } from './convert' +import { Orderable, OrderedContainer } from './OrderedContainer' +import { Context } from './Context' +import { bootstrap } from './bootstrap' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' + +async function main() { + // prepare in memory blockchains + const context = await bootstrap() + + // synchronize to blockchain + const BATCH_SIZE = 10 + + const users = new OrderedContainer( + getNextUsers, + (user: CreatedUserDb) => user.createdAt, + (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) + ) + + await synchronizeToBlockchain(context, [users], BATCH_SIZE) + + // log blockchains + for(const community of context.communities.values()) { + context.logger.info(`Community '${community.communityId}', blockchain`) + logBlogchain(context.logger, community.blockchain) + } + context.db.close() + return Promise.resolve() +} + +async function synchronizeToBlockchain( + context: Context, + containers: Orderable[], + batchSize: number +): Promise { + let rounds = 20 + while (rounds-- > 0) { + await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) + // console.log(`filled containers, rounds left: ${rounds}`) + // remove empty containers + const available = containers.filter(c => !c.isEmpty()) + if (available.length === 0) break + // console.log(`available containers: ${available.length}`) + + // find container with smallest date + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + // console.log(`smallest date: ${available[0].getDate()}`) + + if(rounds >= 0) { + await available[0].pushToBlockchain(context) + } else { + const user = (available[0] as any as OrderedContainer).shift() + console.log(JSON.stringify(user, null, 2)) + console.log(`context: ${JSON.stringify(context, null, 2)}`) + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + const transactionBase = userDbToTransaction(user, communityContext.topicId) + console.log(JSON.stringify(transactionBase, null, 2)) + const registerAddressRole = new RegisterAddressTransactionRole(transactionBase) + const builder = await registerAddressRole.getGradidoTransactionBuilder() + const transaction = builder.build() + console.log(transaction.toJson(true)) + const createdAtTimestamp = new Timestamp(user.createdAt) + console.log(`createdAtTimestamp: ${createdAtTimestamp.toJson()}`) + const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) + const interactionSerialize = new InteractionSerialize(transactionId) + const serializedTransactionId = interactionSerialize.run() + if (serializedTransactionId) { + console.log(`serialized transaction id: ${serializedTransactionId.convertToHex()}`) + } + console.log(communityContext.blockchain) + try { + communityContext.blockchain.createAndAddConfirmedTransaction(transaction, serializedTransactionId, createdAtTimestamp) + } catch(e) { + console.log(e) + } + } + // console.log(`pushed to blockchain, rounds left: ${rounds}`) + } +} + +async function fillBlockchains(context: Context): Promise { + const BATCH_SIZE = 10 + + const users = new OrderedContainer( + getNextUsers, + (user: CreatedUserDb) => user.createdAt, + (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) + ) + /*const transactions = new OrderedContainer(getNextTransactions, (transaction) => transaction.balanceDate) + const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) + const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) +*/ + await synchronizeToBlockchain(context, [users], BATCH_SIZE) +} + +// ---------------- load from db graiddo backend transactions format ----------------------------------------------- +/// load next max ${count} users and calculate key pair for calculating signatures later +async function getNextUsers(context: Context, offset: number, count: number): Promise { + const users = await loadUsers(context.db, offset, count) + for (const user of users) { + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + } + return users +} + +// load next max ${count} transactions (contain also redeem transaction link transactions) +async function getNextTransactions(context: Context, offset: number, count: number): Promise { + return loadTransactions(context.db, offset, count) +} + +// load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) +async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { + return loadTransactionLinks(context.db, offset, count) +} + +// load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) +async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { + return loadDeletedTransactionLinks(context.db, offset, count) +} + +// ---------------- put into in memory blockchain ----------------------------------------------- + +async function pushRegisterAddressTransaction(context: Context, user: CreatedUserDb): Promise { + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + const transaction = userDbToTransaction(user, communityContext.topicId) + return await addRegisterAddressTransaction(communityContext.blockchain, transaction) +} + +/* +async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { + const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) + const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) + // CreationTransactionRole will check that community topic id belongs to home community + context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) + const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) + await addTransaction(senderCommunityContext.blockchain, transaction) +} +*/ +function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { + const f = new Filter() + f.pagination.size = 0 + f.searchDirection = SearchDirection_ASC + + const transactions = blockchain.findAll(f) + for(let i = 0; i < transactions.size(); i++) { + const transaction = transactions.get(i) + const confirmedTransaction = transaction?.getConfirmedTransaction() + logger.info(confirmedTransaction?.toJson(true)) + } +} + + +main().catch((e) => { + // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here + console.error(e) + process.exit(1) +}) \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts new file mode 100644 index 000000000..67337a656 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts @@ -0,0 +1,56 @@ +import { CommunityDb, UserDb } from './database' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { CONFIG } from '../../config' +import { HieroId } from '../../schemas/typeGuard.schema' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.keyPair`) + +export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairCacheManager, topicId: HieroId): void { + let seed: MemoryBlock | null = null + if (community.foreign) { + const randomBuffer = Buffer.alloc(32) + for (let i = 0; i < 32; i++) { + randomBuffer[i] = Math.floor(Math.random() * 256) + } + seed = new MemoryBlock(randomBuffer) + } else { + seed = new MemoryBlock(CONFIG.HOME_COMMUNITY_SEED) + } + const keyPair = KeyPairEd25519.create(seed) + if (!keyPair) { + throw new Error(`Couldn't create key pair for community ${community.communityUuid}`) + } + const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId }).getKey() + cache.addKeyPair(communityKeyPairKey, keyPair) + logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`) +} + +export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheManager, communityTopicId: HieroId): void { + const communityKeyPair = cache.findKeyPair(communityTopicId)! + const userKeyPair = new UserKeyPairRole(user.gradidoId, communityKeyPair).generateKeyPair() + const userKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 0 + } + }).getKey() + cache.addKeyPair(userKeyPairKey, userKeyPair) + + const accountKeyPair = new AccountKeyPairRole(1, userKeyPair).generateKeyPair() + const accountKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 1 + } + }).getKey() + cache.addKeyPair(accountKeyPairKey, accountKeyPair) + logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) +} \ No newline at end of file diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 3d68cfe24..d5ca78ea3 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -28,6 +28,18 @@ export const dateSchema = v.pipe( }), ) +export const booleanSchema = v.pipe( + v.union([v.boolean('expect boolean type'), v.number('expect boolean number type'), v.string('expect boolean string type')]), + v.transform((input) => { + if (typeof input === 'number') { + return input != 0 + } else if (typeof input === 'string') { + return input === 'true' + } + return input + }), +) + /** * AddressType is defined in gradido-blockchain C++ Code * AccountType is the enum defined in TypeScript but with the same options From 74bc448b96edb51478354e9f2e68b35bec6d302d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 31 Oct 2025 10:59:09 +0100 Subject: [PATCH 086/226] refine migration code structure --- .../blockchain.ts | 55 +++++++---------- .../db-v2.7.0_to_blockchain-v3.6/convert.ts | 10 +++- .../db-v2.7.0_to_blockchain-v3.6/database.ts | 57 ++++++++++-------- .../db-v2.7.0_to_blockchain-v3.6/index.ts | 60 ++++++++++++------- .../db-v2.7.0_to_blockchain-v3.6/keyPair.ts | 22 ++++--- docker-compose.yml | 2 + nginx/gradido.conf | 26 ++++++++ 7 files changed, 142 insertions(+), 90 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts index 22fa9b400..4154b0ba9 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts @@ -32,6 +32,7 @@ import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Community, Transaction } from '../../schemas/transaction.schema' import { communityDbToCommunity, userDbToTransaction } from './convert' +import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -60,39 +61,27 @@ export async function addRegisterAddressTransaction(blockchain: InMemoryBlockcha throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) } } -/* - -export async function addTransaction(blockchain: InMemoryBlockchain, transactionDb: TransactionDb): Promise { - - let transactionRole: AbstractTransactionRole - switch (transactionDb.typeId) { - case TransactionTypeId.CREATION: - transactionRole = new CreationTransactionRole({ - user: { - communityTopicId: transactionDb.user.communityTopicId, - account: { - userUuid: transactionDb.user.gradidoId, - accountNr: 0, - }, - }, - linkedUser: { - communityTopicId: transactionDb.linkedUser.communityTopicId, - account: { - userUuid: transactionDb.linkedUser.gradidoId, - accountNr: 0, - }, - }, - amount: v.parse(gradidoAmountSchema, transactionDb.amount), - memo: v.parse(memoSchema, transactionDb.memo), - createdAt: transactionDb.creationDate, - targetDate: transactionDb.balanceDate, - type: getInputTransactionTypeFromTypeId(transactionDb.typeId), - }) - if(addToBlockchain(await transactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transactionDb.creationDate))) { - logger.info(`Transaction added for user ${transactionDb.user.gradidoId}`) - } else { - throw new Error(`Transaction not added for user ${transactionDb.user.gradidoId}`) +export async function addTransaction( + senderBlockchain: InMemoryBlockchain, + _recipientBlockchain: InMemoryBlockchain, + transaction: Transaction +): Promise { + const createdAtTimestamp = new Timestamp(transaction.createdAt) + if (transaction.type === InputTransactionType.GRADIDO_CREATION) { + const creationTransactionRole = new CreationTransactionRole(transaction) + if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.info(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) + } + } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { + const transferTransactionRole = new TransferTransactionRole(transaction) + // will crash with cross group transaction + if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.info(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } } } -*/ \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts index f182664bc..e8052df88 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts @@ -39,7 +39,11 @@ export function userDbToTransaction(userDb: CreatedUserDb, communityTopicId: Hie }) } -export function transactionDbToTransaction(transactionDb: TransactionDb, communityTopicId: HieroId, recipientCommunityTopicId: HieroId): Transaction { +export function transactionDbToTransaction( + transactionDb: TransactionDb, + communityTopicId: HieroId, + recipientCommunityTopicId: HieroId +): Transaction { if ( transactionDb.typeId !== TransactionTypeId.CREATION && transactionDb.typeId !== TransactionTypeId.SEND @@ -48,11 +52,11 @@ export function transactionDbToTransaction(transactionDb: TransactionDb, communi } const user = { communityTopicId: communityTopicId, - account: { userUuid: transactionDb.user.gradidoId }, + account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, } const linkedUser = { communityTopicId: recipientCommunityTopicId, - account: { userUuid: transactionDb.linkedUser.gradidoId }, + account: { userUuid: transactionDb.linkedUser.gradidoId, accountNr: 0 }, } const transaction: TransactionInput = { user, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts index 71561e33d..ce990a76f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts @@ -1,5 +1,5 @@ import { SQL } from 'bun' -import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema } from '../../schemas/typeGuard.schema' +import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' @@ -26,7 +26,7 @@ export enum TransactionTypeId { export const transactionDbSchema = v.object({ typeId: v.enum(TransactionTypeId), - amount: amountSchema, + amount: gradidoAmountSchema, balanceDate: dateSchema, memo: memoSchema, creationDate: v.nullish(dateSchema), @@ -38,7 +38,7 @@ export const transactionDbSchema = v.object({ export const transactionLinkDbSchema = v.object({ userUuid: uuidv4Schema, code: identifierSeedSchema, - amount: amountSchema, + amount: gradidoAmountSchema, memo: memoSchema, createdAt: dateSchema, validUntil: dateSchema, @@ -85,7 +85,7 @@ export async function loadCommunities(db: SQL): Promise { export async function loadUsers(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT id, gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users + SELECT gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users ORDER by created_at ASC LIMIT ${offset}, ${count} ` @@ -100,38 +100,47 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise export async function loadTransactions(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT type_id, amount, balance_date, memo, creation_date, + SELECT t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, tl.code as transaction_link_code - FROM transactions - LEFT JOIN users u ON transactions.user_id = u.id - LEFT JOIN users lu ON transactions.linked_user_id = lu.id - LEFT JOIN transaction_links tl ON transactions.transaction_link_id = tl.id + FROM transactions as t + LEFT JOIN users u ON t.user_id = u.id + LEFT JOIN users lu ON t.linked_user_id = lu.id + LEFT JOIN transaction_links tl ON t.transaction_link_id = tl.id ORDER by balance_date ASC LIMIT ${offset}, ${count} ` return result.map((row: any) => { + // console.log(row) let amount = GradidoUnit.fromString(row.amount) if (row.type_id === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) } - return v.parse(transactionDbSchema, { - typeId: row.type_id, - amount, - balanceDate: new Date(row.balance_date), - memo: row.memo, - creationDate: new Date(row.creation_date), - transactionLinkCode: row.transaction_link_code, - user: { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - }, - linkedUser: { - gradidoId: row.linked_user_gradido_id, - communityUuid: row.linked_user_community_uuid + try { + return v.parse(transactionDbSchema, { + typeId: row.type_id, + amount, + balanceDate: new Date(row.balance_date), + memo: row.memo, + creationDate: new Date(row.creation_date), + transactionLinkCode: row.transaction_link_code, + user: { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + }, + linkedUser: { + gradidoId: row.linked_user_gradido_id, + communityUuid: row.linked_user_community_uuid + } + }) + } catch (e) { + if (e instanceof v.ValiError) { + console.error(v.flatten(e.issues)) + } else { + throw e } - }) + } }) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts index 201526fbb..2aaa02366 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts @@ -9,7 +9,7 @@ import { import { Logger } from 'log4js' import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' -import { addRegisterAddressTransaction, defaultHieroAccount } from './blockchain' +import { addRegisterAddressTransaction, addTransaction, defaultHieroAccount } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' import { transactionDbToTransaction, userDbToTransaction } from './convert' import { Orderable, OrderedContainer } from './OrderedContainer' @@ -17,20 +17,35 @@ import { Context } from './Context' import { bootstrap } from './bootstrap' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +const publicKeyUserIdMap = new Map() + async function main() { // prepare in memory blockchains const context = await bootstrap() + const startTime = Date.now() + await getNextUsers(context, 0, 110) + const endTime = Date.now() + console.log(`getNextUsers took ${endTime - startTime} ms`) + // synchronize to blockchain const BATCH_SIZE = 10 const users = new OrderedContainer( - getNextUsers, + (context: Context, offset: number, count: number) => loadUsers(context.db, offset, count), (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) + const transactions = new OrderedContainer( + getNextTransactions, + (transaction: TransactionDb) => transaction.balanceDate, + (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) + ) - await synchronizeToBlockchain(context, [users], BATCH_SIZE) + // const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) + // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) + + await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) // log blockchains for(const community of context.communities.values()) { @@ -60,7 +75,16 @@ async function synchronizeToBlockchain( // console.log(`smallest date: ${available[0].getDate()}`) if(rounds >= 0) { - await available[0].pushToBlockchain(context) + try { + await available[0].pushToBlockchain(context) + } catch (e) { + console.error(e) + logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + // for(const [key, value] of publicKeyUserIdMap.entries()) { + // console.log(`${key}: ${value}`) + // } + throw e + } } else { const user = (available[0] as any as OrderedContainer).shift() console.log(JSON.stringify(user, null, 2)) @@ -91,28 +115,16 @@ async function synchronizeToBlockchain( } } -async function fillBlockchains(context: Context): Promise { - const BATCH_SIZE = 10 - - const users = new OrderedContainer( - getNextUsers, - (user: CreatedUserDb) => user.createdAt, - (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) - ) - /*const transactions = new OrderedContainer(getNextTransactions, (transaction) => transaction.balanceDate) - const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) - const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) -*/ - await synchronizeToBlockchain(context, [users], BATCH_SIZE) -} - // ---------------- load from db graiddo backend transactions format ----------------------------------------------- + /// load next max ${count} users and calculate key pair for calculating signatures later async function getNextUsers(context: Context, offset: number, count: number): Promise { const users = await loadUsers(context.db, offset, count) for (const user of users) { const communityContext = context.getCommunityContextByUuid(user.communityUuid) - generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + const { userKeyPair, accountKeyPair } = await generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) + publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) } return users } @@ -140,16 +152,18 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse return await addRegisterAddressTransaction(communityContext.blockchain, transaction) } -/* + async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) // CreationTransactionRole will check that community topic id belongs to home community context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, transaction) + await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) } -*/ + +// ---------------- utils ---------------------------------------------------------------------- + function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { const f = new Filter() f.pagination.size = 0 diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts index 67337a656..d5d471210 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts @@ -1,7 +1,7 @@ import { CommunityDb, UserDb } from './database' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { CONFIG } from '../../config' @@ -31,19 +31,23 @@ export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairC logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`) } -export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheManager, communityTopicId: HieroId): void { +export async function generateKeyPairUserAccount( + user: UserDb, + cache: KeyPairCacheManager, + communityTopicId: HieroId +): Promise<{userKeyPair: MemoryBlockPtr, accountKeyPair: MemoryBlockPtr}> { const communityKeyPair = cache.findKeyPair(communityTopicId)! - const userKeyPair = new UserKeyPairRole(user.gradidoId, communityKeyPair).generateKeyPair() + const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair) const userKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, account: { userUuid: user.gradidoId, accountNr: 0 } - }).getKey() - cache.addKeyPair(userKeyPairKey, userKeyPair) + }).getKey() + const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => Promise.resolve(userKeyPairRole.generateKeyPair())) - const accountKeyPair = new AccountKeyPairRole(1, userKeyPair).generateKeyPair() + const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) const accountKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, account: { @@ -51,6 +55,10 @@ export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheMana accountNr: 1 } }).getKey() - cache.addKeyPair(accountKeyPairKey, accountKeyPair) + const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) + return { + userKeyPair: userKeyPair.getPublicKey()!, + accountKeyPair: accountKeyPair.getPublicKey()! + } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d2d88cc9c..c8e23557b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -71,6 +71,8 @@ services: context: ./inspector dockerfile: Dockerfile target: production + profiles: + - dlt networks: - internal-net ports: diff --git a/nginx/gradido.conf b/nginx/gradido.conf index bbfd8db51..edaf12d22 100644 --- a/nginx/gradido.conf +++ b/nginx/gradido.conf @@ -82,4 +82,30 @@ server { proxy_redirect off; } + # Inspector + location /inspector { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://inspector:3100; + proxy_redirect off; + } + + # Gradido Node + location /dlt { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://dlt-connector:8340/api; + proxy_redirect off; + } + } From bf39551416c4f4c0b7f9f90f4f8f5a321b195e39 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Sat, 1 Nov 2025 08:21:31 +0100 Subject: [PATCH 087/226] correct path, add migration into dlt-connector/package.json --- dlt-connector/log4js-config.json | 6 +- dlt-connector/package.json | 1 + dlt-connector/src/bootstrap/init.ts | 2 +- .../Context.ts | 7 +- .../OrderedContainer.ts | 0 .../blockchain.ts | 6 +- .../bootstrap.ts | 0 .../convert.ts | 1 + .../database.ts | 25 +++++-- .../index.ts | 67 ++++++++++++++----- .../keyPair.ts | 2 +- 11 files changed, 81 insertions(+), 36 deletions(-) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/Context.ts (87%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/OrderedContainer.ts (100%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/blockchain.ts (93%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/bootstrap.ts (100%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/convert.ts (99%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/database.ts (86%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/index.ts (76%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/keyPair.ts (96%) diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 66127eb80..8d865fa26 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c - %m" }, "compress": true, "keepFileExt" : true, @@ -21,7 +21,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] - %m" }, "compress": true, "keepFileExt" : true, @@ -53,7 +53,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c - %m" } } }, diff --git a/dlt-connector/package.json b/dlt-connector/package.json index e1bef07c9..78c3c1b96 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -10,6 +10,7 @@ "start": "bun run src/index.ts", "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify", "dev": "bun run --watch src/index.ts", + "migrate": "cross-env MIMALLOC_SHOW_STATS=1 bun src/migrations/db-v2.7.0_to_blockchain-v3.5", "test": "bun test", "test:debug": "bun test --inspect-brk", "typecheck": "tsc --noEmit", diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index 13b77783c..e0289db57 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -39,7 +39,7 @@ export async function checkHomeCommunity( // wait for backend server await isPortOpenRetry(backend.url) // ask backend for home community - let homeCommunity = await backend.getHomeCommunityDraft() + let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.hieroTopicId) { const topicId = await hiero.createTopic(homeCommunity.name) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts similarity index 87% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index b60a08b08..dde47b7c4 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,13 +1,13 @@ import { SQL } from 'bun' import { InMemoryBlockchain } from 'gradido-blockchain-js' -import { Logger } from 'log4js' +import { getLogger, Logger } from 'log4js' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { loadConfig } from '../../bootstrap/init' import { CONFIG } from '../../config' - +import { LOG4JS_BASE_CATEGORY } from '../../config/const' export type CommunityContext = { communityId: string @@ -29,8 +29,9 @@ export class Context { } static create(): Context { + loadConfig() return new Context( - loadConfig(), + getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), new SQL({ adapter: 'mysql', hostname: CONFIG.MYSQL_HOST, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts similarity index 100% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts similarity index 93% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 4154b0ba9..9d1e43409 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -56,7 +56,7 @@ export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { const registerAddressRole = new RegisterAddressTransactionRole(transaction) if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { - logger.info(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) } @@ -71,7 +71,7 @@ export async function addTransaction( if (transaction.type === InputTransactionType.GRADIDO_CREATION) { const creationTransactionRole = new CreationTransactionRole(transaction) if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.info(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) } @@ -79,7 +79,7 @@ export async function addTransaction( const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.info(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts similarity index 100% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts similarity index 99% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts index e8052df88..a455aa1e1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts @@ -50,6 +50,7 @@ export function transactionDbToTransaction( && transactionDb.typeId !== TransactionTypeId.RECEIVE) { throw new Error('not implemented') } + const user = { communityTopicId: communityTopicId, account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts similarity index 86% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index ce990a76f..bdd377821 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -3,6 +3,8 @@ import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAm import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { getLogger } from 'log4js' export const createdUserDbSchema = v.object({ gradidoId: uuidv4Schema, @@ -59,6 +61,8 @@ export type CreatedUserDb = v.InferOutput export type TransactionLinkDb = v.InferOutput export type CommunityDb = v.InferOutput +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) + // queries export async function loadCommunities(db: SQL): Promise { const result = await db` @@ -89,10 +93,6 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise ORDER by created_at ASC LIMIT ${offset}, ${count} ` - const totalCount = await db` - SELECT COUNT(*) as count FROM users - ` - console.log(`Loaded ${result.length} users, total ${totalCount[0].count} with offset ${offset} and count ${count}`) return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) @@ -100,9 +100,9 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise export async function loadTransactions(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, - u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, - lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, + SELECT t.id, t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, + u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, u.created_at as user_created_at, + lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, lu.created_at as linked_user_created_at, tl.code as transaction_link_code FROM transactions as t LEFT JOIN users u ON t.user_id = u.id @@ -113,6 +113,17 @@ export async function loadTransactions(db: SQL, offset: number, count: number): ` return result.map((row: any) => { // console.log(row) + // check for consistent data beforehand + const userCreatedAt = new Date(row.user_created_at) + const linkedUserCreatedAd = new Date(row.linked_user_created_at) + const balanceDate = new Date(row.balance_date) + if (userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ){ + logger.error(`table row: `, row) + throw new Error('at least one user was created after transaction balance date, logic error!') + } + let amount = GradidoUnit.fromString(row.amount) if (row.type_id === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts similarity index 76% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 2aaa02366..113f37aa1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -4,7 +4,8 @@ import { SearchDirection_ASC, HieroTransactionId, Timestamp, - InteractionSerialize + InteractionSerialize, + Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' @@ -16,23 +17,20 @@ import { Orderable, OrderedContainer } from './OrderedContainer' import { Context } from './Context' import { bootstrap } from './bootstrap' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { heapStats } from 'bun:jsc' const publicKeyUserIdMap = new Map() async function main() { + const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() - const startTime = Date.now() - await getNextUsers(context, 0, 110) - const endTime = Date.now() - console.log(`getNextUsers took ${endTime - startTime} ms`) - // synchronize to blockchain - const BATCH_SIZE = 10 + const BATCH_SIZE = 100 const users = new OrderedContainer( - (context: Context, offset: number, count: number) => loadUsers(context.db, offset, count), + (context: Context, offset: number, count: number) => getNextUsers(context, offset, count), (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) @@ -46,22 +44,40 @@ async function main() { // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) - - // log blockchains - for(const community of context.communities.values()) { - context.logger.info(`Community '${community.communityId}', blockchain`) - logBlogchain(context.logger, community.blockchain) - } + context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) + timeUsed.reset() + context.communities.forEach((communityContext) => { + const f = new Filter() + // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS + f.pagination.size = 0 + const transactions = communityContext.blockchain.findAll(f) + context.logger.info(`Community '${communityContext.communityId}', transactions: ${transactions.size()}`) + // logBlogchain(context.logger, communityContext.blockchain) + }) + context.logger.info(`${timeUsed.string()} for logging blockchains`) context.db.close() + const runtimeStats = heapStats() + /* + heapSize: 24254530, + heapCapacity: 32191922, + extraMemorySize: 7003858 + */ + context.logger.info( + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + ) return Promise.resolve() } +function bytesToMbyte(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(4) +} + async function synchronizeToBlockchain( context: Context, containers: Orderable[], batchSize: number ): Promise { - let rounds = 20 + let rounds = 200 while (rounds-- > 0) { await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) // console.log(`filled containers, rounds left: ${rounds}`) @@ -119,6 +135,7 @@ async function synchronizeToBlockchain( /// load next max ${count} users and calculate key pair for calculating signatures later async function getNextUsers(context: Context, offset: number, count: number): Promise { + const timeUsed = new Profiler() const users = await loadUsers(context.db, offset, count) for (const user of users) { const communityContext = context.getCommunityContextByUuid(user.communityUuid) @@ -126,22 +143,36 @@ async function getNextUsers(context: Context, offset: number, count: number): Pr publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) } + if(users.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${users.length} users from db and calculate ed25519 KeyPairs for them`) + } return users } // load next max ${count} transactions (contain also redeem transaction link transactions) async function getNextTransactions(context: Context, offset: number, count: number): Promise { - return loadTransactions(context.db, offset, count) + const timeUsed = new Profiler() + const transactions = await loadTransactions(context.db, offset, count) + if(transactions.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) + } + return transactions } // load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { - return loadTransactionLinks(context.db, offset, count) + const timeUsed = new Profiler() + const transactionLinks = await loadTransactionLinks(context.db, offset, count) + context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + return transactionLinks } // load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { - return loadDeletedTransactionLinks(context.db, offset, count) + const timeUsed = new Profiler() + const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) + context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + return deletedTransactionLinks } // ---------------- put into in memory blockchain ----------------------------------------------- diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts similarity index 96% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index d5d471210..6d30760c5 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -56,7 +56,7 @@ export async function generateKeyPairUserAccount( } }).getKey() const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) - logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) + //logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) return { userKeyPair: userKeyPair.getPublicKey()!, accountKeyPair: accountKeyPair.getPublicKey()! From eb8c806b5dd44e6207a38177954f7a49c288fa67 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 3 Nov 2025 14:25:03 +0100 Subject: [PATCH 088/226] restructure, optimize logging --- dlt-connector/bun.lock | 3 + dlt-connector/package.json | 3 +- .../OrderedContainer.ts | 5 + .../blockchain.ts | 39 +++---- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 27 ++++- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 14 ++- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 109 ++++++++---------- 7 files changed, 108 insertions(+), 92 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 21caa0f07..1f27138de 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -25,6 +25,7 @@ "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", + "yoctocolors-cjs": "^2.1.3", }, }, }, @@ -999,6 +1000,8 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 78c3c1b96..fd33612a5 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -38,7 +38,8 @@ "log4js": "^6.9.1", "typescript": "^5.8.3", "uuid": "^8.3.2", - "valibot": "1.1.0" + "valibot": "1.1.0", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts index 90dcc0e74..47595b3d0 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts @@ -7,6 +7,7 @@ export interface Orderable { ensureFilled(context: ContextType, batchSize: number): Promise pushToBlockchain(context: ContextType): Promise isEmpty(): boolean + get length(): number } export class OrderedContainer implements Orderable { @@ -48,6 +49,10 @@ export class OrderedContainer implements Orderable return item } + get length(): number { + return this.items.length + } + getDate(): Date { return this.getDateHandler(this.peek()) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 9d1e43409..12ba38017 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -1,38 +1,21 @@ -import { sql, SQL } from 'bun' import { InMemoryBlockchain, - InMemoryBlockchainProvider, GradidoTransactionBuilder, - KeyPairEd25519, - MemoryBlock, Timestamp, HieroTransactionId, HieroAccountId, InteractionSerialize, - loadCryptoKeys, - Filter, - SearchDirection_ASC } from 'gradido-blockchain-js' -import { Logger, getLogger } from 'log4js' -import { CONFIG } from '../../config' -import { amountSchema, HieroId, hieroIdSchema, memoSchema, uuidv4Schema, Uuidv4, gradidoAmountSchema } from '../../schemas/typeGuard.schema' -import { dateSchema } from '../../schemas/typeConverter.schema' -import * as v from 'valibot' +import { getLogger } from 'log4js' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' -import { InputTransactionType } from '../../data/InputTransactionType.enum' -import { AccountType } from '../../data/AccountType.enum' import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' -import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' -import { loadConfig } from '../../bootstrap/init' import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' -import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb } from './database' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Community, Transaction } from '../../schemas/transaction.schema' -import { communityDbToCommunity, userDbToTransaction } from './convert' import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' +import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' +import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' +import { InputTransactionType } from '../../data/InputTransactionType.enum' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -83,5 +66,19 @@ export async function addTransaction( } else { throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } + } else if (transaction.type === InputTransactionType.GRADIDO_DEFERRED_TRANSFER) { + const transferTransactionRole = new DeferredTransferTransactionRole(transaction) + if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } + } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction) + if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.debug(`Redeem Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Redeem Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } } } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts index a455aa1e1..747e6c2ef 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts @@ -1,8 +1,8 @@ import { InputTransactionType } from '../../data/InputTransactionType.enum' -import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb } from './database' +import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb, TransactionLinkDb } from './database' import { Community, communitySchema, transactionSchema, Transaction, TransactionInput } from '../../schemas/transaction.schema' import { AccountType } from '../../data/AccountType.enum' -import { gradidoAmountSchema, HieroId, memoSchema } from '../../schemas/typeGuard.schema' +import { gradidoAmountSchema, HieroId, memoSchema, timeoutDurationSchema } from '../../schemas/typeGuard.schema' import * as v from 'valibot' export function getInputTransactionTypeFromTypeId(typeId: TransactionTypeId): InputTransactionType { @@ -53,11 +53,11 @@ export function transactionDbToTransaction( const user = { communityTopicId: communityTopicId, - account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, + account: { userUuid: transactionDb.user.gradidoId }, } const linkedUser = { communityTopicId: recipientCommunityTopicId, - account: { userUuid: transactionDb.linkedUser.gradidoId, accountNr: 0 }, + account: { userUuid: transactionDb.linkedUser.gradidoId }, } const transaction: TransactionInput = { user, @@ -89,3 +89,22 @@ export function transactionDbToTransaction( } return v.parse(transactionSchema, transaction) } + +export function transactionLinkDbToTransaction(transactionLinkDb: TransactionLinkDb, communityTopicId: HieroId): Transaction { + return v.parse(transactionSchema, { + user: { + communityTopicId: communityTopicId, + account: { userUuid: transactionLinkDb.user.gradidoId }, + }, + linkedUser: { + communityTopicId: communityTopicId, + seed: transactionLinkDb.code, + }, + type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, + amount: v.parse(gradidoAmountSchema, transactionLinkDb.amount), + memo: v.parse(memoSchema, transactionLinkDb.memo), + createdAt: transactionLinkDb.createdAt, + timeoutDuration: v.parse(timeoutDurationSchema, Math.round((transactionLinkDb.validUntil.getTime() - transactionLinkDb.createdAt.getTime()) / 1000)), + }) +} + diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index bdd377821..f63a7a002 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -1,5 +1,5 @@ import { SQL } from 'bun' -import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' +import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' @@ -38,7 +38,7 @@ export const transactionDbSchema = v.object({ }) export const transactionLinkDbSchema = v.object({ - userUuid: uuidv4Schema, + user: userDbSchema, code: identifierSeedSchema, amount: gradidoAmountSchema, memo: memoSchema, @@ -157,14 +157,20 @@ export async function loadTransactions(db: SQL, offset: number, count: number): export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT u.gradido_id as userUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil + SELECT u.gradido_id as userGradidoId, u.community_uuid as userCommunityUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil FROM transaction_links tl LEFT JOIN users u ON tl.userId = u.id ORDER by createdAt ASC LIMIT ${offset}, ${count} ` return result.map((row: any) => { - return v.parse(transactionLinkDbSchema, row) + return v.parse(transactionLinkDbSchema, { + ...row, + user: { + gradidoId: row.userGradidoId, + communityUuid: row.userCommunityUuid + } + }) }) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 113f37aa1..b7edfb6ec 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -2,22 +2,19 @@ import { InMemoryBlockchain, Filter, SearchDirection_ASC, - HieroTransactionId, - Timestamp, - InteractionSerialize, Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' -import { addRegisterAddressTransaction, addTransaction, defaultHieroAccount } from './blockchain' +import { addRegisterAddressTransaction, addTransaction } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' -import { transactionDbToTransaction, userDbToTransaction } from './convert' +import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' import { Orderable, OrderedContainer } from './OrderedContainer' import { Context } from './Context' import { bootstrap } from './bootstrap' -import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' import { heapStats } from 'bun:jsc' +import { onShutdown } from '../../../../shared/src/helper/onShutdown' const publicKeyUserIdMap = new Map() @@ -25,7 +22,13 @@ async function main() { const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() - + onShutdown(async (reason, error) => { + context.logger.info(`shutdown reason: ${reason}`) + if(error) { + context.logger.error(error) + } + context.db.close() + }) // synchronize to blockchain const BATCH_SIZE = 100 @@ -40,10 +43,19 @@ async function main() { (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) - // const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) - // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) + const transactionLinks = new OrderedContainer( + getNextTransactionLinks, + (transactionLink: TransactionLinkDb) => transactionLink.createdAt, + (context: Context, transactionLink: TransactionLinkDb) => pushTransactionLink(context, transactionLink) + ) - await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) + const deletedTransactionLinks = new OrderedContainer( + getNextDeletedTransactionLinks, + (transaction: TransactionDb) => transaction.balanceDate, + (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) + ) + + await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) timeUsed.reset() context.communities.forEach((communityContext) => { @@ -55,17 +67,12 @@ async function main() { // logBlogchain(context.logger, communityContext.blockchain) }) context.logger.info(`${timeUsed.string()} for logging blockchains`) - context.db.close() const runtimeStats = heapStats() - /* - heapSize: 24254530, - heapCapacity: 32191922, - extraMemorySize: 7003858 - */ context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` ) - return Promise.resolve() + // needed because of shutdown handler (TODO: fix shutdown handler) + process.exit(0) } function bytesToMbyte(bytes: number): string { @@ -77,57 +84,26 @@ async function synchronizeToBlockchain( containers: Orderable[], batchSize: number ): Promise { - let rounds = 200 - while (rounds-- > 0) { + while (true) { + const timeUsed = new Profiler() await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - // console.log(`filled containers, rounds left: ${rounds}`) + const itemCount = containers.reduce((acc, c) => acc + c.length, 0) + context.logger.info(`${timeUsed.string()} for ensuring filled containers, ${itemCount} items`) + // remove empty containers const available = containers.filter(c => !c.isEmpty()) if (available.length === 0) break - // console.log(`available containers: ${available.length}`) // find container with smallest date available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) - // console.log(`smallest date: ${available[0].getDate()}`) - if(rounds >= 0) { - try { - await available[0].pushToBlockchain(context) - } catch (e) { - console.error(e) - logBlogchain(context.logger, context.communities.values().next().value!.blockchain) - // for(const [key, value] of publicKeyUserIdMap.entries()) { - // console.log(`${key}: ${value}`) - // } - throw e - } - } else { - const user = (available[0] as any as OrderedContainer).shift() - console.log(JSON.stringify(user, null, 2)) - console.log(`context: ${JSON.stringify(context, null, 2)}`) - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const transactionBase = userDbToTransaction(user, communityContext.topicId) - console.log(JSON.stringify(transactionBase, null, 2)) - const registerAddressRole = new RegisterAddressTransactionRole(transactionBase) - const builder = await registerAddressRole.getGradidoTransactionBuilder() - const transaction = builder.build() - console.log(transaction.toJson(true)) - const createdAtTimestamp = new Timestamp(user.createdAt) - console.log(`createdAtTimestamp: ${createdAtTimestamp.toJson()}`) - const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) - const interactionSerialize = new InteractionSerialize(transactionId) - const serializedTransactionId = interactionSerialize.run() - if (serializedTransactionId) { - console.log(`serialized transaction id: ${serializedTransactionId.convertToHex()}`) - } - console.log(communityContext.blockchain) - try { - communityContext.blockchain.createAndAddConfirmedTransaction(transaction, serializedTransactionId, createdAtTimestamp) - } catch(e) { - console.log(e) - } + try { + await available[0].pushToBlockchain(context) + } catch (e) { + console.error(e) + logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + throw e } - // console.log(`pushed to blockchain, rounds left: ${rounds}`) } } @@ -163,7 +139,9 @@ async function getNextTransactions(context: Context, offset: number, count: numb async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { const timeUsed = new Profiler() const transactionLinks = await loadTransactionLinks(context.db, offset, count) - context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + if(transactionLinks.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + } return transactionLinks } @@ -171,7 +149,9 @@ async function getNextTransactionLinks(context: Context, offset: number, count: async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { const timeUsed = new Profiler() const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) - context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + if(deletedTransactionLinks.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + } return deletedTransactionLinks } @@ -183,7 +163,6 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse return await addRegisterAddressTransaction(communityContext.blockchain, transaction) } - async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) @@ -193,6 +172,12 @@ async function pushTransaction(context: Context, transactionDb: TransactionDb): await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) } +async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { + const communityContext = context.getCommunityContextByUuid(transactionLinkDb.user.communityUuid) + const transaction = transactionLinkDbToTransaction(transactionLinkDb, communityContext.topicId) + await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) +} + // ---------------- utils ---------------------------------------------------------------------- function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { From f027bf5b7a965983ddd331457ac36f4de1d122a5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 11:43:51 +0100 Subject: [PATCH 089/226] fix some issues --- dlt-connector/bun.lock | 4 +- dlt-connector/package.json | 2 +- .../RedeemDeferredTransferTransaction.role.ts | 20 +++---- .../sendToHiero/SendToHiero.context.ts | 18 ++++++- .../blockchain.ts | 35 +++++++++--- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 54 +++++++++++++------ 6 files changed, 92 insertions(+), 41 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 1f27138de..7ad790bf3 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -160,11 +160,11 @@ "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], - "@hashgraph/cryptography": ["@hashgraph/cryptography@1.13.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-bttkU9cnbA2NgmE41V4IDYZ5IYMY9HtVTnlvg3fdj8m83+7T4KgTBPPSkqwFCgSeW2x/6MV2GDzvaj4Lx4IYfw=="], + "@hashgraph/cryptography": ["@hashgraph/cryptography@1.14.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-vYeRpkdYHgO0y09BJJms4DQvjkSQuoOWnf1tCaOHfs4w2u1RttQUMgQbaZCM07+6YL3Pq8SPHbcEch5tbSdBNg=="], "@hashgraph/proto": ["@hashgraph/proto@2.24.0", "", { "dependencies": { "long": "5.3.1" }, "peerDependencies": { "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "debug": "4.4.1", "protobufjs": "7.5.4", "strip-ansi": "7.1.2" } }, "sha512-S1eE0CoQ17s40JuzKaKpMze8h0JoN13za5arCp3xaqbWVT4UEFq/O/zJud9cpZ31uYwpPe8gH65TPZ3pKd9ZWQ=="], - "@hashgraph/sdk": ["@hashgraph/sdk@2.75.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.13.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-Nkv57So2RbNlKxog1nsyqHgorgrStr3yzx0ZWse4R6yg1TztafiqA2+9m3YlmH3eNMr7vmghgtGqPkRflfVhZg=="], + "@hashgraph/sdk": ["@hashgraph/sdk@2.76.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.14.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-FrLDeiHCJak+ZBcRv5cFoX23LPHvn1xWvVIST+oheI0NGfMxOXrGLWICaP5FMWdOnLfkM1OklCQ93J+QBFP7+Q=="], "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index fd33612a5..b314584c6 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -10,7 +10,7 @@ "start": "bun run src/index.ts", "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify", "dev": "bun run --watch src/index.ts", - "migrate": "cross-env MIMALLOC_SHOW_STATS=1 bun src/migrations/db-v2.7.0_to_blockchain-v3.5", + "migrate": "bun src/migrations/db-v2.7.0_to_blockchain-v3.5", "test": "bun test", "test:debug": "bun test --inspect-brk", "typecheck": "tsc --noEmit", diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 626712404..2f51f8f21 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,6 +1,5 @@ -import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { ConfirmedTransaction, GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' import * as v from 'valibot' -import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { RedeemDeferredTransferTransaction, @@ -15,12 +14,14 @@ import { AbstractTransactionRole } from './AbstractTransaction.role' export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRole { private linkedUser: UserAccount private readonly redeemDeferredTransferTransaction: RedeemDeferredTransferTransaction - constructor(transaction: Transaction) { + private readonly parentDeferredTransaction: ConfirmedTransaction + constructor(transaction: Transaction, parentDeferredTransaction: ConfirmedTransaction) { super() this.redeemDeferredTransferTransaction = v.parse( redeemDeferredTransferTransactionSchema, transaction, ) + this.parentDeferredTransaction = parentDeferredTransaction this.linkedUser = this.redeemDeferredTransferTransaction.linkedUser } @@ -41,16 +42,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo if (!senderPublicKey) { throw new Error("redeem deferred transfer: couldn't calculate sender public key") } - // load deferred transfer transaction from gradido node - const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( - { maxResultCount: 2, topic: this.getSenderCommunityTopicId() }, - senderPublicKey.convertToHex(), - ) - if (!transactions || transactions.length !== 1) { - throw new Error("redeem deferred transfer: couldn't find deferred transfer on Gradido Node") - } - const deferredTransfer = transactions[0] - const deferredTransferBody = deferredTransfer.getGradidoTransaction()?.getTransactionBody() + const deferredTransferBody = this.parentDeferredTransaction.getGradidoTransaction()?.getTransactionBody() if (!deferredTransferBody) { throw new Error( "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", @@ -61,7 +53,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo builder .setCreatedAt(this.redeemDeferredTransferTransaction.createdAt) .setRedeemDeferredTransfer( - deferredTransfer.getId(), + this.parentDeferredTransaction.getId(), new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 5b5f1f629..5ef946ec9 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -6,6 +6,7 @@ import { ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import * as v from 'valibot' import { ensureCommunitiesAvailable } from '../../client/GradidoNode/communities' import { HieroClient } from '../../client/hiero/HieroClient' @@ -21,6 +22,7 @@ import { HieroId, HieroTransactionIdString, hieroTransactionIdStringSchema, + identifierSeedSchema, } from '../../schemas/typeGuard.schema' import { isTopicStillOpen } from '../../utils/hiero' import { AbstractTransactionRole } from './AbstractTransaction.role' @@ -30,6 +32,7 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' +import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) @@ -144,7 +147,20 @@ async function chooseCorrectRole( case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: return new DeferredTransferTransactionRole(transaction) case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: - return new RedeemDeferredTransferTransactionRole(transaction) + // load deferred transfer transaction from gradido node + const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() + if (!seedPublicKey) { + throw new Error("redeem deferred transfer: couldn't generate seed public key") + } + const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( + { maxResultCount: 2, topic: transaction.user.communityTopicId }, + seedPublicKey.convertToHex(), + ) + if (!transactions || transactions.length !== 1) { + throw new Error("redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node") + } + return new RedeemDeferredTransferTransactionRole(transaction, transactions[0]) default: throw new Error('not supported transaction type: ' + transaction.type) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 12ba38017..2d135b184 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -4,7 +4,8 @@ import { Timestamp, HieroTransactionId, HieroAccountId, - InteractionSerialize, + InteractionSerialize, + Filter, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' @@ -16,6 +17,9 @@ import { TransferTransactionRole } from '../../interactions/sendToHiero/Transfer import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { LinkedTransactionKeyPairRole } from '../../interactions/resolveKeyPair/LinkedTransactionKeyPair.role' +import { identifierSeedSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -24,7 +28,13 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor const transaction = builder.build() const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) - return blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + try { + const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + return result + } catch (error) { + logger.error(`Transaction ${transaction.toJson(true)} not added: ${error}`) + return false + } } export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { @@ -57,7 +67,7 @@ export async function addTransaction( logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) - } + } } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction @@ -71,14 +81,27 @@ export async function addTransaction( if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { + throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { - const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction) + const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const f = new Filter() + f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() + const deferredTransaction = senderBlockchain.findOne(f) + if (!deferredTransaction) { + throw new Error("redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node") + } + const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() + if (!confirmedDeferredTransaction) { + throw new Error("redeem deferred transfer: invalid TransactionEntry") + } + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction, confirmedDeferredTransaction) + const involvedUser = transaction.user.account ? transaction.user.account.userUuid : transaction.linkedUser?.account?.userUuid if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.debug(`Redeem Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Redeem Deferred Transfer Transaction added for user ${involvedUser}`) } else { - throw new Error(`Redeem Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error(`Redeem Deferred Transfer Transaction not added for user ${involvedUser}`) } } } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index b7edfb6ec..8d66db750 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -15,6 +15,7 @@ import { Context } from './Context' import { bootstrap } from './bootstrap' import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' +import { sleep } from 'bun' const publicKeyUserIdMap = new Map() @@ -29,6 +30,7 @@ async function main() { } context.db.close() }) + // synchronize to blockchain const BATCH_SIZE = 100 @@ -54,11 +56,15 @@ async function main() { (transaction: TransactionDb) => transaction.balanceDate, (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) - - await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + try { + await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + } catch (e) { + console.error(e) + throw e + } context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - timeUsed.reset() - context.communities.forEach((communityContext) => { + // timeUsed.reset() + /*context.communities.forEach((communityContext) => { const f = new Filter() // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS f.pagination.size = 0 @@ -67,6 +73,7 @@ async function main() { // logBlogchain(context.logger, communityContext.blockchain) }) context.logger.info(`${timeUsed.string()} for logging blockchains`) + */ const runtimeStats = heapStats() context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` @@ -84,24 +91,33 @@ async function synchronizeToBlockchain( containers: Orderable[], batchSize: number ): Promise { - while (true) { - const timeUsed = new Profiler() - await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - const itemCount = containers.reduce((acc, c) => acc + c.length, 0) - context.logger.info(`${timeUsed.string()} for ensuring filled containers, ${itemCount} items`) + const timeUsed = new Profiler() + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) + const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) + // log only, if at least one new item was loaded + if (loadedItemsCount && context.logger.isInfoEnabled()) { + context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) + } // remove empty containers const available = containers.filter(c => !c.isEmpty()) - if (available.length === 0) break + if (available.length === 0) { + break + } // find container with smallest date - available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + if (available.length > 0) { + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + } try { await available[0].pushToBlockchain(context) + // await sleep(1) } catch (e) { - console.error(e) - logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + context.logger.error(e) + // logBlogchain(context.logger, context.communities.values().next().value!.blockchain) throw e } } @@ -130,8 +146,8 @@ async function getNextTransactions(context: Context, offset: number, count: numb const timeUsed = new Profiler() const transactions = await loadTransactions(context.db, offset, count) if(transactions.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) - } + context.logger.debug(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) + } return transactions } @@ -140,7 +156,7 @@ async function getNextTransactionLinks(context: Context, offset: number, count: const timeUsed = new Profiler() const transactionLinks = await loadTransactionLinks(context.db, offset, count) if(transactionLinks.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + context.logger.debug(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) } return transactionLinks } @@ -150,7 +166,7 @@ async function getNextDeletedTransactionLinks(context: Context, offset: number, const timeUsed = new Profiler() const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) if(deletedTransactionLinks.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + context.logger.debug(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) } return deletedTransactionLinks } @@ -165,11 +181,15 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) + // context.logger.info(`before adding non register address and non link transaction:`) + // logBlogchain(context.logger, senderCommunityContext.blockchain) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) // CreationTransactionRole will check that community topic id belongs to home community context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + // const firstTransaction = senderCommunityContext.blockchain.findOne(Filter.FIRST_TRANSACTION) + // console.log(`first transaction: ${firstTransaction?.getConfirmedTransaction()?.toJson(true)}`) } async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { From cbd98708254c75cad66ed20b72e3c3aa0f674dd5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 13:29:15 +0100 Subject: [PATCH 090/226] replace bun native mysql code with drizzle orm and mysql2 as driver --- dlt-connector/bun.lock | 34 +++- dlt-connector/package.json | 2 + .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 26 +-- .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 158 ++++++++---------- .../drizzle.schema.ts | 53 ++++++ .../db-v2.7.0_to_blockchain-v3.5/index.ts | 14 +- 7 files changed, 186 insertions(+), 103 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 7ad790bf3..f4dcee45b 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -17,11 +17,13 @@ "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", + "drizzle-orm": "^0.44.7", "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", + "mysql2": "^3.15.3", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", @@ -322,6 +324,8 @@ "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "axios": ["axios@0.24.0", "", { "dependencies": { "follow-redirects": "^1.14.4" } }, "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA=="], "babel-jest": ["babel-jest@29.7.0", "", { "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg=="], @@ -426,12 +430,16 @@ "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "dotenv": ["dotenv@10.0.0", "", {}, "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="], + "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], @@ -530,6 +538,8 @@ "gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], + "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], @@ -578,6 +588,8 @@ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], @@ -598,6 +610,8 @@ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="], + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -662,7 +676,9 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + + "lru.min": ["lru.min@1.1.2", "", {}, "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg=="], "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], @@ -730,6 +746,10 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="], + + "named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], + "nan": ["nan@2.23.0", "", {}, "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ=="], "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], @@ -856,6 +876,8 @@ "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], @@ -864,6 +886,8 @@ "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + "serialize-error": ["serialize-error@2.1.0", "", {}, "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="], "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], @@ -894,6 +918,8 @@ "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], @@ -1008,6 +1034,8 @@ "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/traverse/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -1072,8 +1100,6 @@ "log4js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "metro/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], @@ -1118,6 +1144,8 @@ "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index b314584c6..749258400 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -31,11 +31,13 @@ "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", + "drizzle-orm": "^0.44.7", "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", + "mysql2": "^3.15.3", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index dde47b7c4..5708cccd3 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,4 +1,5 @@ -import { SQL } from 'bun' +import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' +import mysql from 'mysql2/promise' import { InMemoryBlockchain } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' @@ -17,29 +18,30 @@ export type CommunityContext = { export class Context { public logger: Logger - public db: SQL + public db: MySql2Database public communities: Map public cache: KeyPairCacheManager - constructor(logger: Logger, db: SQL, cache: KeyPairCacheManager) { + constructor(logger: Logger, db: MySql2Database, cache: KeyPairCacheManager) { this.logger = logger this.db = db this.cache = cache this.communities = new Map() } - static create(): Context { + static async create(): Promise { loadConfig() + + const connection = await mysql.createConnection({ + host: CONFIG.MYSQL_HOST, + user: CONFIG.MYSQL_USER, + password: CONFIG.MYSQL_PASSWORD, + database: CONFIG.MYSQL_DATABASE, + port: CONFIG.MYSQL_PORT + }) return new Context( getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), - new SQL({ - adapter: 'mysql', - hostname: CONFIG.MYSQL_HOST, - username: CONFIG.MYSQL_USER, - password: CONFIG.MYSQL_PASSWORD, - database: CONFIG.MYSQL_DATABASE, - port: CONFIG.MYSQL_PORT - }), + drizzle({ client: connection }), KeyPairCacheManager.getInstance() ) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index 325347369..f987d579e 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -9,7 +9,7 @@ import { communityDbToCommunity } from './convert' import { addCommunityRootTransaction } from './blockchain' export async function bootstrap(): Promise { - const context = Context.create() + const context = await Context.create() context.communities = await bootstrapCommunities(context) return context } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index f63a7a002..125c9fb71 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -1,10 +1,13 @@ -import { SQL } from 'bun' import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' -import { GradidoUnit } from 'gradido-blockchain-js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { getLogger } from 'log4js' +import { MySql2Database } from 'drizzle-orm/mysql2' +import { communitiesTable, transactionLinksTable, transactionsTable, usersTable } from './drizzle.schema' +import { asc, sql, eq, isNotNull } from 'drizzle-orm' +import { alias } from 'drizzle-orm/mysql-core' +import { GradidoUnit } from 'gradido-blockchain-js' export const createdUserDbSchema = v.object({ gradidoId: uuidv4Schema, @@ -64,14 +67,19 @@ export type CommunityDb = v.InferOutput const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) // queries -export async function loadCommunities(db: SQL): Promise { - const result = await db` - SELECT c.foreign, c.community_uuid as communityUuid, c.name as name, c.creation_date as creationDate, MIN(u.created_at) as userMinCreatedAt - FROM communities c - LEFT JOIN users u ON c.community_uuid = u.community_uuid - WHERE c.community_uuid IS NOT NULL - GROUP BY c.community_uuid - ` +export async function loadCommunities(db: MySql2Database): Promise { + const result = await db.select({ + foreign: communitiesTable.foreign, + communityUuid: communitiesTable.communityUuid, + name: communitiesTable.name, + creationDate: communitiesTable.creationDate, + userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, + }) + .from(communitiesTable) + .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) + .where(isNotNull(communitiesTable.communityUuid)) + .groupBy(communitiesTable.communityUuid) + const communityNames = new Set() return result.map((row: any) => { let alias = row.name @@ -87,36 +95,39 @@ export async function loadCommunities(db: SQL): Promise { }) } -export async function loadUsers(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users - ORDER by created_at ASC - LIMIT ${offset}, ${count} - ` +export async function loadUsers(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(usersTable) + .orderBy(asc(usersTable.createdAt)) + .limit(count).offset(offset) + return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) } -export async function loadTransactions(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT t.id, t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, - u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, u.created_at as user_created_at, - lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, lu.created_at as linked_user_created_at, - tl.code as transaction_link_code - FROM transactions as t - LEFT JOIN users u ON t.user_id = u.id - LEFT JOIN users lu ON t.linked_user_id = lu.id - LEFT JOIN transaction_links tl ON t.transaction_link_id = tl.id - ORDER by balance_date ASC - LIMIT ${offset}, ${count} - ` +export async function loadTransactions(db: MySql2Database, offset: number, count: number): Promise { + const linkedUsers = alias(usersTable, 'linkedUser') + + const result = await db.select({ + transaction: transactionsTable, + user: usersTable, + linkedUser: linkedUsers, + transactionLink: transactionLinksTable, + }) + .from(transactionsTable) + .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) + .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) + .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) + .orderBy(asc(transactionsTable.balanceDate)) + .limit(count).offset(offset) + return result.map((row: any) => { // console.log(row) // check for consistent data beforehand - const userCreatedAt = new Date(row.user_created_at) - const linkedUserCreatedAd = new Date(row.linked_user_created_at) - const balanceDate = new Date(row.balance_date) + const userCreatedAt = new Date(row.user.createdAt) + const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) + const balanceDate = new Date(row.transaction.balanceDate) if (userCreatedAt.getTime() > balanceDate.getTime() || linkedUserCreatedAd.getTime() > balanceDate.getTime() ){ @@ -124,79 +135,58 @@ export async function loadTransactions(db: SQL, offset: number, count: number): throw new Error('at least one user was created after transaction balance date, logic error!') } - let amount = GradidoUnit.fromString(row.amount) - if (row.type_id === TransactionTypeId.SEND) { + let amount = GradidoUnit.fromString(row.transaction.amount) + if (row.transaction.typeId === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) } try { return v.parse(transactionDbSchema, { - typeId: row.type_id, - amount, - balanceDate: new Date(row.balance_date), - memo: row.memo, - creationDate: new Date(row.creation_date), - transactionLinkCode: row.transaction_link_code, - user: { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - }, - linkedUser: { - gradidoId: row.linked_user_gradido_id, - communityUuid: row.linked_user_community_uuid - } + ...row.transaction, + transactionLinkCode: row.transactionLink ? row.transactionLink.code : null, + user: row.user, + linkedUser: row.linkedUser, }) } catch (e) { if (e instanceof v.ValiError) { - console.error(v.flatten(e.issues)) - } else { - throw e + logger.error(v.flatten(e.issues)) } + throw e } }) } -export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT u.gradido_id as userGradidoId, u.community_uuid as userCommunityUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil - FROM transaction_links tl - LEFT JOIN users u ON tl.userId = u.id - ORDER by createdAt ASC - LIMIT ${offset}, ${count} - ` +export async function loadTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .orderBy(asc(transactionLinksTable.createdAt)) + .limit(count).offset(offset) + return result.map((row: any) => { return v.parse(transactionLinkDbSchema, { - ...row, - user: { - gradidoId: row.userGradidoId, - communityUuid: row.userCommunityUuid - } + ...row.transaction_links, + user: row.users, }) }) } -export async function loadDeletedTransactionLinks(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT u.gradido_id as user_gradido_id, u.community_uuid as user_community_uuid, - tl.code, tl.amount, tl.memo, tl.deletedAt - FROM transaction_links tl - LEFT JOIN users u ON tl.userId = u.id - WHERE deletedAt IS NOT NULL - ORDER by deletedAt ASC - LIMIT ${offset}, ${count} - ` +export async function loadDeletedTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .where(isNotNull(transactionLinksTable.deletedAt)) + .orderBy(asc(transactionLinksTable.deletedAt)) + .limit(count).offset(offset) + return result.map((row: any) => { - const user = { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - } return v.parse(transactionDbSchema, { typeId: TransactionTypeId.RECEIVE, - amount: row.amount, - balanceDate: new Date(row.deletedAt), - memo: row.memo, - transactionLinkCode: row.code, - user, - linkedUser: user + amount: row.transaction_links.amount, + balanceDate: new Date(row.transaction_links.deletedAt), + memo: row.transaction_links.memo, + transactionLinkCode: row.transaction_links.code, + user: row.users, + linkedUser: row.users }) }) } \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts new file mode 100644 index 000000000..12c92eaa9 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -0,0 +1,53 @@ + +import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' +import { sql } from 'drizzle-orm' + + +// use only fields needed in the migration, after update the rest of the project, import database instead +export const communitiesTable = mysqlTable('communities', { + foreign: tinyint().default(1).notNull(), + communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), + name: varchar({ length: 40 }).default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), +}, +(table) => [ + unique('uuid_key').on(table.communityUuid), +]) + + +export const usersTable = mysqlTable('users', { + id: int().autoincrement().notNull(), + gradidoId: char('gradido_id', { length: 36 }).notNull(), + communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), + createdAt: datetime('created_at', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), +}, +(table) => [ + unique('uuid_key').on(table.gradidoId, table.communityUuid), +]) + +export const transactionsTable = mysqlTable('transactions', { + id: int().autoincrement().notNull(), + typeId: int("type_id").default(sql`NULL`), + transactionLinkId: int("transaction_link_id").default(sql`NULL`), + amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), + balanceDate: datetime("balance_date", { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), + memo: varchar({ length: 255 }).notNull(), + creationDate: datetime("creation_date", { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int("user_id").notNull(), + linkedUserId: int("linked_user_id").default(sql`NULL`), +}, +(table) => [ + index("user_id").on(table.userId), +]) + + +export const transactionLinksTable = mysqlTable('transaction_links', { + id: int().autoincrement().notNull(), + userId: int().notNull(), + amount: decimal({ precision: 40, scale: 20 }).notNull(), + memo: varchar({ length: 255 }).notNull(), + code: varchar({ length: 24 }).notNull(), + createdAt: datetime({ mode: 'string'}).notNull(), + deletedAt: datetime({ mode: 'string'}).default(sql`NULL`), + validUntil: datetime({ mode: 'string'}).notNull(), +}) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 8d66db750..1c309d021 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -5,8 +5,15 @@ import { Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' - -import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' +import { + CreatedUserDb, + loadDeletedTransactionLinks, + loadTransactionLinks, + loadTransactions, + loadUsers, + TransactionDb, + TransactionLinkDb +} from './database' import { addRegisterAddressTransaction, addTransaction } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' @@ -28,7 +35,6 @@ async function main() { if(error) { context.logger.error(error) } - context.db.close() }) // synchronize to blockchain @@ -39,6 +45,7 @@ async function main() { (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) + const transactions = new OrderedContainer( getNextTransactions, (transaction: TransactionDb) => transaction.balanceDate, @@ -56,6 +63,7 @@ async function main() { (transaction: TransactionDb) => transaction.balanceDate, (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) + try { await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) } catch (e) { From f09c8e917d83345bba7055df1fec681d33298f17 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 14:17:23 +0100 Subject: [PATCH 091/226] move some code into interaction --- .../OrderedContainer.ts | 63 ------- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 168 +----------------- .../syncDbWithBlockchain/AbstractSync.role.ts | 67 +++++++ .../DeletedTransactionLinksSync.role.ts | 13 ++ .../TransactionLinksSync.role.ts | 25 +++ .../TransactionsSync.role.ts | 27 +++ .../syncDbWithBlockchain/UsersSync.role.ts | 32 ++++ .../syncDbWithBlockchain.context.ts | 39 ++++ 8 files changed, 205 insertions(+), 229 deletions(-) delete mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts deleted file mode 100644 index 47595b3d0..000000000 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts +++ /dev/null @@ -1,63 +0,0 @@ - -export type Loader = (context: ContextType, offset: number, count: number) => Promise - -export interface Orderable { - getDate(): Date - // return count of new loaded items - ensureFilled(context: ContextType, batchSize: number): Promise - pushToBlockchain(context: ContextType): Promise - isEmpty(): boolean - get length(): number -} - -export class OrderedContainer implements Orderable { - private items: T[] = [] - private offset = 0 - - constructor( - private readonly loader: Loader, - private readonly getDateHandler: (item: T) => Date, - private readonly pushToBlockchainHandler: (context: ContextType, item: T) => Promise - ) {} - - - async ensureFilled(context: ContextType, batchSize: number): Promise { - if (this.items.length === 0) { - this.items = await this.loader(context, this.offset, batchSize) - this.offset += this.items.length - return this.items.length - } - return 0 - } - - async pushToBlockchain(context: ContextType): Promise { - return this.pushToBlockchainHandler(context, this.shift()) - } - - peek(): T { - if (this.isEmpty()) { - throw new Error(`[peek] No items, please call this only if isEmpty returns false`) - } - return this.items[0] - } - - shift(): T { - const item = this.items.shift() - if (!item) { - throw new Error(`[shift] No items, shift return undefined`) - } - return item - } - - get length(): number { - return this.items.length - } - - getDate(): Date { - return this.getDateHandler(this.peek()) - } - - isEmpty(): boolean { - return this.items.length === 0 - } -} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 1c309d021..14a85e9bf 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -5,26 +5,11 @@ import { Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' -import { - CreatedUserDb, - loadDeletedTransactionLinks, - loadTransactionLinks, - loadTransactions, - loadUsers, - TransactionDb, - TransactionLinkDb -} from './database' -import { addRegisterAddressTransaction, addTransaction } from './blockchain' -import { generateKeyPairUserAccount } from './keyPair' -import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' -import { Orderable, OrderedContainer } from './OrderedContainer' -import { Context } from './Context' import { bootstrap } from './bootstrap' import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' -import { sleep } from 'bun' +import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' -const publicKeyUserIdMap = new Map() async function main() { const timeUsed = new Profiler() @@ -40,48 +25,13 @@ async function main() { // synchronize to blockchain const BATCH_SIZE = 100 - const users = new OrderedContainer( - (context: Context, offset: number, count: number) => getNextUsers(context, offset, count), - (user: CreatedUserDb) => user.createdAt, - (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) - ) - - const transactions = new OrderedContainer( - getNextTransactions, - (transaction: TransactionDb) => transaction.balanceDate, - (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) - ) - - const transactionLinks = new OrderedContainer( - getNextTransactionLinks, - (transactionLink: TransactionLinkDb) => transactionLink.createdAt, - (context: Context, transactionLink: TransactionLinkDb) => pushTransactionLink(context, transactionLink) - ) - - const deletedTransactionLinks = new OrderedContainer( - getNextDeletedTransactionLinks, - (transaction: TransactionDb) => transaction.balanceDate, - (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) - ) - try { - await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + await syncDbWithBlockchainContext(context, BATCH_SIZE) } catch (e) { console.error(e) throw e } context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - // timeUsed.reset() - /*context.communities.forEach((communityContext) => { - const f = new Filter() - // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS - f.pagination.size = 0 - const transactions = communityContext.blockchain.findAll(f) - context.logger.info(`Community '${communityContext.communityId}', transactions: ${transactions.size()}`) - // logBlogchain(context.logger, communityContext.blockchain) - }) - context.logger.info(`${timeUsed.string()} for logging blockchains`) - */ const runtimeStats = heapStats() context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` @@ -94,120 +44,6 @@ function bytesToMbyte(bytes: number): string { return (bytes / 1024 / 1024).toFixed(4) } -async function synchronizeToBlockchain( - context: Context, - containers: Orderable[], - batchSize: number -): Promise { - const timeUsed = new Profiler() - while (true) { - timeUsed.reset() - const results = await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) - // log only, if at least one new item was loaded - if (loadedItemsCount && context.logger.isInfoEnabled()) { - context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) - } - - // remove empty containers - const available = containers.filter(c => !c.isEmpty()) - if (available.length === 0) { - break - } - - // find container with smallest date - if (available.length > 0) { - available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) - } - - try { - await available[0].pushToBlockchain(context) - // await sleep(1) - } catch (e) { - context.logger.error(e) - // logBlogchain(context.logger, context.communities.values().next().value!.blockchain) - throw e - } - } -} - -// ---------------- load from db graiddo backend transactions format ----------------------------------------------- - -/// load next max ${count} users and calculate key pair for calculating signatures later -async function getNextUsers(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const users = await loadUsers(context.db, offset, count) - for (const user of users) { - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const { userKeyPair, accountKeyPair } = await generateKeyPairUserAccount(user, context.cache, communityContext.topicId) - publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) - publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) - } - if(users.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${users.length} users from db and calculate ed25519 KeyPairs for them`) - } - return users -} - -// load next max ${count} transactions (contain also redeem transaction link transactions) -async function getNextTransactions(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const transactions = await loadTransactions(context.db, offset, count) - if(transactions.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) - } - return transactions -} - -// load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) -async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const transactionLinks = await loadTransactionLinks(context.db, offset, count) - if(transactionLinks.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) - } - return transactionLinks -} - -// load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) -async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) - if(deletedTransactionLinks.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) - } - return deletedTransactionLinks -} - -// ---------------- put into in memory blockchain ----------------------------------------------- - -async function pushRegisterAddressTransaction(context: Context, user: CreatedUserDb): Promise { - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const transaction = userDbToTransaction(user, communityContext.topicId) - return await addRegisterAddressTransaction(communityContext.blockchain, transaction) -} - -async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { - const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) - // context.logger.info(`before adding non register address and non link transaction:`) - // logBlogchain(context.logger, senderCommunityContext.blockchain) - const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) - // CreationTransactionRole will check that community topic id belongs to home community - context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) - const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) - // const firstTransaction = senderCommunityContext.blockchain.findOne(Filter.FIRST_TRANSACTION) - // console.log(`first transaction: ${firstTransaction?.getConfirmedTransaction()?.toJson(true)}`) -} - -async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { - const communityContext = context.getCommunityContextByUuid(transactionLinkDb.user.communityUuid) - const transaction = transactionLinkDbToTransaction(transactionLinkDb, communityContext.topicId) - await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) -} - -// ---------------- utils ---------------------------------------------------------------------- - function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { const f = new Filter() f.pagination.size = 0 diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts new file mode 100644 index 000000000..44fd0b471 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -0,0 +1,67 @@ +import { Context } from '../../Context' +import { getLogger, Logger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../../../config/const' +import { Profiler } from 'gradido-blockchain-js' + +export abstract class AbstractSyncRole { + private items: T[] = [] + private offset = 0 + protected logger: Logger + + constructor(protected readonly context: Context) { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`) + } + + abstract getDate(): Date + abstract loadFromDb(offset: number, count: number): Promise + abstract pushToBlockchain(item: T): Promise + abstract itemTypeName(): string + + // return count of new loaded items + async ensureFilled(batchSize: number): Promise + { + if (this.items.length === 0) { + let timeUsed: Profiler | undefined + if (this.logger.isDebugEnabled()) { + timeUsed = new Profiler() + } + this.items = await this.loadFromDb(this.offset, batchSize) + this.offset += this.items.length + if (timeUsed && this.items.length) { + this.logger.debug(`${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`) + } + return this.items.length + } + return 0 + } + + async toBlockchain(): Promise { + if (this.isEmpty()) { + throw new Error(`[toBlockchain] No items, please call this only if isEmpty returns false`) + } + await this.pushToBlockchain(this.shift()) + } + + peek(): T { + if (this.isEmpty()) { + throw new Error(`[peek] No items, please call this only if isEmpty returns false`) + } + return this.items[0] + } + + shift(): T { + const item = this.items.shift() + if (!item) { + throw new Error(`[shift] No items, shift return undefined`) + } + return item + } + + get length(): number { + return this.items.length + } + + isEmpty(): boolean { + return this.items.length === 0 + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts new file mode 100644 index 000000000..d4e8eaa6e --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -0,0 +1,13 @@ +import { loadDeletedTransactionLinks } from '../../database' +import { TransactionsSyncRole } from './TransactionsSync.role' +import { TransactionDb } from '../../database' + +export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { + itemTypeName(): string { + return 'deletedTransactionLinks' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadDeletedTransactionLinks(this.context.db, offset, count) + } +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts new file mode 100644 index 000000000..c4d5e94d7 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -0,0 +1,25 @@ +import { TransactionLinkDb, loadTransactionLinks } from '../../database' +import { transactionLinkDbToTransaction } from '../../convert' +import { addTransaction } from '../../blockchain' +import { AbstractSyncRole } from './AbstractSync.role' + +export class TransactionLinksSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().createdAt + } + + itemTypeName(): string { + return 'transactionLinks' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadTransactionLinks(this.context.db, offset, count) + } + + async pushToBlockchain(item: TransactionLinkDb): Promise { + const communityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) + const transaction = transactionLinkDbToTransaction(item, communityContext.topicId) + await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) + } +} + \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts new file mode 100644 index 000000000..2f05e4378 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts @@ -0,0 +1,27 @@ +import { TransactionDb, loadTransactions } from '../../database' +import { transactionDbToTransaction } from '../../convert' +import { addTransaction } from '../../blockchain' +import { AbstractSyncRole } from './AbstractSync.role' + +export class TransactionsSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().balanceDate + } + + itemTypeName(): string { + return 'transactions' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadTransactions(this.context.db, offset, count) + } + + async pushToBlockchain(item: TransactionDb): Promise { + const senderCommunityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) + const recipientCommunityContext = this.context.getCommunityContextByUuid(item.linkedUser.communityUuid) + this.context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) + const transaction = transactionDbToTransaction(item, senderCommunityContext.topicId, recipientCommunityContext.topicId) + await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + } +} + \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts new file mode 100644 index 000000000..ca4799b68 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -0,0 +1,32 @@ +import { CreatedUserDb } from '../../database' +import { AbstractSyncRole } from './AbstractSync.role' +import { loadUsers } from '../../database' +import { generateKeyPairUserAccount } from '../../keyPair' +import { userDbToTransaction } from '../../convert' +import { addRegisterAddressTransaction } from '../../blockchain' + + +export class UsersSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().createdAt + } + + itemTypeName(): string { + return 'users' + } + + async loadFromDb(offset: number, count: number): Promise { + const users = await loadUsers(this.context.db, offset, count) + for (const user of users) { + const communityContext = this.context.getCommunityContextByUuid(user.communityUuid) + await generateKeyPairUserAccount(user, this.context.cache, communityContext.topicId) + } + return users + } + + async pushToBlockchain(item: CreatedUserDb): Promise { + const communityContext = this.context.getCommunityContextByUuid(item.communityUuid) + const transaction = userDbToTransaction(item, communityContext.topicId) + return await addRegisterAddressTransaction(communityContext.blockchain, transaction) + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts new file mode 100644 index 000000000..edef30caa --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts @@ -0,0 +1,39 @@ +import { Context } from '../../Context' +import { Profiler } from 'gradido-blockchain-js' +import { TransactionsSyncRole } from './TransactionsSync.role' +import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' +import { TransactionLinksSyncRole } from './TransactionLinksSync.role' +import { UsersSyncRole } from './UsersSync.role' + +export async function syncDbWithBlockchainContext(context: Context, batchSize: number) { + const timeUsed = new Profiler() + const containers = [ + new UsersSyncRole(context), + new TransactionsSyncRole(context), + new DeletedTransactionLinksSyncRole(context), + new TransactionLinksSyncRole(context) + ] + + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map(c => c.ensureFilled(batchSize))) + const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) + // log only, if at least one new item was loaded + if (loadedItemsCount && context.logger.isInfoEnabled()) { + context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) + } + + // remove empty containers + const available = containers.filter(c => !c.isEmpty()) + if (available.length === 0) { + break + } + + // sort by date, to ensure container on index 0 is the one with the smallest date + if (available.length > 0) { + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + } + await available[0].toBlockchain() + } +} + From 72c0b3d8df011118d79041344f16d525343589f3 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 6 Nov 2025 12:37:34 +0100 Subject: [PATCH 092/226] try to fix deploy script --- deployment/bare_metal/start.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index cb53206a5..580123a75 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -214,14 +214,13 @@ unset FEDERATION_APIVERSION unset FEDERATION_PORT log_step "====================================================================================================" +export DLT_NGINX_CONF="${DLT_NGINX_CONF:-# dlt disabled}" # prepare inspector and gradido dlt node nginx config blocks if enabled if [ "$DLT_CONNECTOR" = true ] ; then log_step "prepare inspector and dlt gradido node nginx config block" envsubst '$DLT_NODE_SERVER_PORT' < $NGINX_CONFIG_DIR/gradido-dlt.conf.template >> $NGINX_CONFIG_DIR/gradido-dlt.conf export DLT_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-dlt.conf) rm $NGINX_CONFIG_DIR/gradido-dlt.conf -else - export DLT_NGINX_CONF="# dlt is disabled" fi # *** 2nd read gradido-federation.conf file in env variable to be replaced in 3rd step From 290a6a4f27630d50d631100698f7abd29c8c50ae Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 8 Nov 2025 12:47:49 +0100 Subject: [PATCH 093/226] refactor, finalize export to blockchain file --- dlt-connector/bun.lock | 19 +++++ dlt-connector/package.json | 1 + .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 40 ++++++++-- .../TransactionTypeId.ts | 8 ++ .../binaryExport.ts | 76 +++++++++++++++++++ .../blockchain.ts | 1 + .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 5 +- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 3 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 68 +++-------------- .../drizzle.schema.ts | 17 ++--- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 51 +++---------- .../DeletedTransactionLinksSync.role.ts | 2 +- .../TransactionLinksSync.role.ts | 3 +- .../TransactionsSync.role.ts | 3 +- .../syncDbWithBlockchain/UsersSync.role.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/keyPair.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/utils.ts | 15 ++++ .../valibot.schema.ts | 66 ++++++++++++++++ 18 files changed, 259 insertions(+), 123 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index f4dcee45b..6f6fd84d4 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -24,6 +24,7 @@ "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", "mysql2": "^3.15.3", + "sodium-native": "5.0.9", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", @@ -342,6 +343,18 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "bare-addon-resolve": ["bare-addon-resolve@1.9.5", "", { "dependencies": { "bare-module-resolve": "^1.10.0", "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-XdqrG73zLK9LDfblOJwoAxmJ+7YdfRW4ex46+f4L+wPhk7H7LDrRMAbBw8s8jkxeEFpUenyB7QHnv0ErAWd3Yg=="], + + "bare-module-resolve": ["bare-module-resolve@1.11.2", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-HIBu9WacMejg3Dz4X1v6lJjp7ECnwpujvuLub+8I7JJLRwJaGxWMzGYvieOoS9R1n5iRByvTmLtIdPbwjfRgiQ=="], + + "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="], + + "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], + + "bare-semver": ["bare-semver@1.0.2", "", {}, "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA=="], + + "bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.8.20", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ=="], @@ -862,6 +875,8 @@ "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], + "require-addon": ["require-addon@1.1.0", "", { "dependencies": { "bare-addon-resolve": "^1.3.0", "bare-url": "^2.1.0" } }, "sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], @@ -906,6 +921,8 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], "source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], @@ -1006,6 +1023,8 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which-runtime": ["which-runtime@1.3.2", "", {}, "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw=="], + "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 749258400..c4c6f1099 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -38,6 +38,7 @@ "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", "mysql2": "^3.15.3", + "sodium-native": "5.0.9", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index 5708cccd3..9eb549a30 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,32 +1,31 @@ import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' import mysql from 'mysql2/promise' -import { InMemoryBlockchain } from 'gradido-blockchain-js' +import { Filter, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' -import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' +import { Uuidv4 } from '../../schemas/typeGuard.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { loadConfig } from '../../bootstrap/init' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' - -export type CommunityContext = { - communityId: string - blockchain: InMemoryBlockchain - topicId: HieroId -} +import { heapStats } from 'bun:jsc' +import { CommunityContext } from './valibot.schema' +import { bytesToMbyte } from './utils' export class Context { public logger: Logger public db: MySql2Database public communities: Map public cache: KeyPairCacheManager + private timeUsed: Profiler constructor(logger: Logger, db: MySql2Database, cache: KeyPairCacheManager) { this.logger = logger this.db = db this.cache = cache this.communities = new Map() + this.timeUsed = new Profiler() } static async create(): Promise { @@ -53,4 +52,29 @@ export class Context { } return community } + + logRuntimeStatistics() { + this.logger.info(`${this.timeUsed.string()} for synchronizing to blockchain`) + const runtimeStats = heapStats() + this.logger.info( + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + ) + } + + logBlogchain(communityUuid: Uuidv4) { + const communityContext = this.getCommunityContextByUuid(communityUuid) + const f = new Filter() + f.pagination.size = 0 + f.searchDirection = SearchDirection_ASC + + const transactions = communityContext.blockchain.findAll(f) + for(let i = 0; i < transactions.size(); i++) { + const transaction = transactions.get(i) + const confirmedTransaction = transaction?.getConfirmedTransaction() + this.logger.info(confirmedTransaction?.toJson(true)) + } + } + + // TODO: move into utils + } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts new file mode 100644 index 000000000..dc5fc25e0 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts @@ -0,0 +1,8 @@ +export enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts new file mode 100644 index 000000000..74181f34f --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -0,0 +1,76 @@ +import { ConfirmedTransaction, Filter, InteractionSerialize, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' +import path from 'node:path' +import { CONFIG } from '../../config' +import fs from 'node:fs' +import { bytesToKbyte } from './utils' +import { calculateOneHashStep } from './utils' +import { Context } from './Context' +import { CommunityContext } from './valibot.schema' + +export function exportAllCommunities(context: Context, batchSize: number) { + const timeUsed = new Profiler() + for(const communityContext of context.communities.values()) { + exportCommunity(communityContext, context, batchSize) + } + context.logger.info(`time used for exporting communities to binary file: ${timeUsed.string()}`) +} + +export function exportCommunity(communityContext: CommunityContext, context: Context, batchSize: number) { + // write as binary file for GradidoNode + const f = new Filter() + f.pagination.size = batchSize + f.pagination.page = 1 + f.searchDirection = SearchDirection_ASC + const binFilePath = prepareFolder(communityContext) + + let lastTransactionCount = 0 + let hash = Buffer.alloc(32, 0) + do { + const transactions = communityContext.blockchain.findAll(f) + lastTransactionCount = transactions.size() + + for (let i = 0; i < lastTransactionCount; i++) { + const confirmedTransaction = transactions.get(i)?.getConfirmedTransaction() + const transactionNr = f.pagination.page * batchSize + i + if (!confirmedTransaction) { + throw new Error(`invalid TransactionEntry at index: ${transactionNr} `) + } + hash = exportTransaction(confirmedTransaction, hash, binFilePath) + } + f.pagination.page++ + } while (lastTransactionCount === batchSize) + + fs.appendFileSync(binFilePath, hash!) + context.logger.info(`binary file for community ${communityContext.communityId} written to ${binFilePath}`) + context.logger.info( + `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte` + ) +} + +function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buffer, binFilePath: string): Buffer { + const sizeBuffer = Buffer.alloc(2) + const interactionSerialize = new InteractionSerialize(confirmedTransaction) + const binBlock = interactionSerialize.run() + if (!binBlock) { + throw new Error(`invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`) + } + + hash = calculateOneHashStep(hash, binBlock.data()) + sizeBuffer.writeUInt16LE(binBlock.size(), 0) + fs.appendFileSync(binFilePath, sizeBuffer) + fs.appendFileSync(binFilePath, binBlock.data()) + return hash +} + +function prepareFolder(communityContext: CommunityContext): string { + const binFileFolder = path.join( + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + '.gradido', + communityContext.folder, + ) + const binFilePath = path.join(binFileFolder, 'blk00000001.dat') + // make sure we work with a clean folder, rm beforehand with all content + fs.rmSync(binFileFolder, { recursive: true }) + fs.mkdirSync(binFileFolder, { recursive: true }) + return binFilePath +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 2d135b184..5a09065a8 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -28,6 +28,7 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor const transaction = builder.build() const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) + try { const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) return result diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index f987d579e..ef792e8d6 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -1,5 +1,4 @@ import { Context } from './Context' -import { CommunityContext } from './Context' import { loadCommunities } from './database' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import * as v from 'valibot' @@ -7,6 +6,7 @@ import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' import { generateKeyPairCommunity } from './keyPair' import { communityDbToCommunity } from './convert' import { addCommunityRootTransaction } from './blockchain' +import { CommunityContext } from './valibot.schema' export async function bootstrap(): Promise { const context = await Context.create() @@ -35,7 +35,8 @@ async function bootstrapCommunities(context: Context): Promise -export type UserDb = v.InferOutput -export type CreatedUserDb = v.InferOutput -export type TransactionLinkDb = v.InferOutput -export type CommunityDb = v.InferOutput +import { + CommunityDb, + communityDbSchema, + CreatedUserDb, + createdUserDbSchema, + TransactionDb, + transactionDbSchema, + TransactionLinkDb, + transactionLinkDbSchema +} from './valibot.schema' +import { TransactionTypeId } from './TransactionTypeId' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts index 12c92eaa9..f96b71bfe 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -2,7 +2,6 @@ import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' import { sql } from 'drizzle-orm' - // use only fields needed in the migration, after update the rest of the project, import database instead export const communitiesTable = mysqlTable('communities', { foreign: tinyint().default(1).notNull(), @@ -14,7 +13,6 @@ export const communitiesTable = mysqlTable('communities', { unique('uuid_key').on(table.communityUuid), ]) - export const usersTable = mysqlTable('users', { id: int().autoincrement().notNull(), gradidoId: char('gradido_id', { length: 36 }).notNull(), @@ -27,20 +25,19 @@ export const usersTable = mysqlTable('users', { export const transactionsTable = mysqlTable('transactions', { id: int().autoincrement().notNull(), - typeId: int("type_id").default(sql`NULL`), - transactionLinkId: int("transaction_link_id").default(sql`NULL`), + typeId: int('type_id').default(sql`NULL`), + transactionLinkId: int('transaction_link_id').default(sql`NULL`), amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), - balanceDate: datetime("balance_date", { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), + balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), memo: varchar({ length: 255 }).notNull(), - creationDate: datetime("creation_date", { mode: 'string', fsp: 3 }).default(sql`NULL`), - userId: int("user_id").notNull(), - linkedUserId: int("linked_user_id").default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int('user_id').notNull(), + linkedUserId: int('linked_user_id').default(sql`NULL`), }, (table) => [ - index("user_id").on(table.userId), + index('user_id').on(table.userId), ]) - export const transactionLinksTable = mysqlTable('transaction_links', { id: int().autoincrement().notNull(), userId: int().notNull(), diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 14a85e9bf..5bae06fee 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -1,18 +1,12 @@ -import { - InMemoryBlockchain, - Filter, - SearchDirection_ASC, - Profiler -} from 'gradido-blockchain-js' -import { Logger } from 'log4js' import { bootstrap } from './bootstrap' -import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' +import { exportAllCommunities } from './binaryExport' +import { Filter } from 'gradido-blockchain-js' +const BATCH_SIZE = 100 async function main() { - const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() onShutdown(async (reason, error) => { @@ -22,42 +16,19 @@ async function main() { } }) - // synchronize to blockchain - const BATCH_SIZE = 100 + // synchronize to in memory blockchain + await syncDbWithBlockchainContext(context, BATCH_SIZE) + + // write as binary file for GradidoNode + exportAllCommunities(context, BATCH_SIZE) + + // log runtime statistics + context.logRuntimeStatistics() - try { - await syncDbWithBlockchainContext(context, BATCH_SIZE) - } catch (e) { - console.error(e) - throw e - } - context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - const runtimeStats = heapStats() - context.logger.info( - `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` - ) // needed because of shutdown handler (TODO: fix shutdown handler) process.exit(0) } -function bytesToMbyte(bytes: number): string { - return (bytes / 1024 / 1024).toFixed(4) -} - -function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { - const f = new Filter() - f.pagination.size = 0 - f.searchDirection = SearchDirection_ASC - - const transactions = blockchain.findAll(f) - for(let i = 0; i < transactions.size(); i++) { - const transaction = transactions.get(i) - const confirmedTransaction = transaction?.getConfirmedTransaction() - logger.info(confirmedTransaction?.toJson(true)) - } -} - - main().catch((e) => { // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts index d4e8eaa6e..2ff3961b1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -1,6 +1,6 @@ import { loadDeletedTransactionLinks } from '../../database' import { TransactionsSyncRole } from './TransactionsSync.role' -import { TransactionDb } from '../../database' +import { TransactionDb } from '../../valibot.schema' export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { itemTypeName(): string { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts index c4d5e94d7..30706dba3 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -1,4 +1,5 @@ -import { TransactionLinkDb, loadTransactionLinks } from '../../database' +import { TransactionLinkDb } from '../../valibot.schema' +import { loadTransactionLinks } from '../../database' import { transactionLinkDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' import { AbstractSyncRole } from './AbstractSync.role' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts index 2f05e4378..b2ca9d75f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts @@ -1,4 +1,5 @@ -import { TransactionDb, loadTransactions } from '../../database' +import { TransactionDb } from '../../valibot.schema' +import { loadTransactions } from '../../database' import { transactionDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' import { AbstractSyncRole } from './AbstractSync.role' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts index ca4799b68..acdf5011d 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -1,4 +1,4 @@ -import { CreatedUserDb } from '../../database' +import { CreatedUserDb } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' import { loadUsers } from '../../database' import { generateKeyPairUserAccount } from '../../keyPair' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index 6d30760c5..dda017cbd 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -1,4 +1,4 @@ -import { CommunityDb, UserDb } from './database' +import { CommunityDb, UserDb } from './valibot.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts new file mode 100644 index 000000000..57ae73137 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts @@ -0,0 +1,15 @@ +import { crypto_generichash_batch, crypto_generichash_KEYBYTES } from 'sodium-native' + +export function bytesToMbyte(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(4) +} + +export function bytesToKbyte(bytes: number): string { + return (bytes / 1024).toFixed(0) +} + +export function calculateOneHashStep(hash: Buffer, data: Buffer): Buffer { + const outputHash = Buffer.alloc(crypto_generichash_KEYBYTES, 0) + crypto_generichash_batch(outputHash, [hash, data]) + return outputHash +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts new file mode 100644 index 000000000..354a62543 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts @@ -0,0 +1,66 @@ +import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' +import { TransactionTypeId } from './TransactionTypeId' +import { InMemoryBlockchain } from 'gradido-blockchain-js' +import * as v from 'valibot' + +export const createdUserDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, + createdAt: dateSchema, +}) + +export const userDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, +}) + + +export const transactionDbSchema = v.object({ + typeId: v.enum(TransactionTypeId), + amount: gradidoAmountSchema, + balanceDate: dateSchema, + memo: memoSchema, + creationDate: v.nullish(dateSchema), + user: userDbSchema, + linkedUser: userDbSchema, + transactionLinkCode: v.nullish(identifierSeedSchema), +}) + +export const transactionLinkDbSchema = v.object({ + user: userDbSchema, + code: identifierSeedSchema, + amount: gradidoAmountSchema, + memo: memoSchema, + createdAt: dateSchema, + validUntil: dateSchema, +}) + +export const communityDbSchema = v.object({ + foreign: booleanSchema, + communityUuid: uuidv4Schema, + name: v.string(), + creationDate: dateSchema, + userMinCreatedAt: dateSchema, + uniqueAlias: v.string(), +}) + +export const communityContextSchema = v.object({ + communityId: v.string(), + blockchain: v.instance(InMemoryBlockchain, 'expect InMemoryBlockchain type'), + topicId: hieroIdSchema, + folder: v.pipe( + v.string(), + v.minLength(1, 'expect string length >= 1'), + v.maxLength(255, 'expect string length <= 255'), + v.regex(/^[a-zA-Z0-9-_]+$/, + 'expect string to be a valid (alphanumeric, _, -) folder name'), + ), +}) + +export type TransactionDb = v.InferOutput +export type UserDb = v.InferOutput +export type CreatedUserDb = v.InferOutput +export type TransactionLinkDb = v.InferOutput +export type CommunityDb = v.InferOutput +export type CommunityContext = v.InferOutput \ No newline at end of file From 98b3a526ef44ad39fbf4be53426313a5c8b8867f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 8 Nov 2025 13:16:51 +0100 Subject: [PATCH 094/226] fix seed algorithmus to get correct data --- backend/src/seeds/factory/user.ts | 6 +++++- backend/src/seeds/transactionLink/index.ts | 3 +-- backend/src/seeds/users/bibi-bloxberg.ts | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 3cae22f71..44db02c8f 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -40,11 +40,15 @@ export const userFactory = async ( } // get last changes of user from database - dbUser = await User.findOneOrFail({ where: { id }, relations: ['userRoles'] }) + dbUser = await User.findOneOrFail({ where: { id }, relations: { userRoles: true, emailContact: true } }) if (user.createdAt || user.deletedAt || user.role) { if (user.createdAt) { dbUser.createdAt = user.createdAt + // make sure emailContact is also updated for e2e test, prevent failing when time between seeding and test run is < 1 minute + dbUser.emailContact.createdAt = user.createdAt + dbUser.emailContact.updatedAt = user.createdAt + await dbUser.emailContact.save() } if (user.deletedAt) { dbUser.deletedAt = user.deletedAt diff --git a/backend/src/seeds/transactionLink/index.ts b/backend/src/seeds/transactionLink/index.ts index c3245c2b6..17683b580 100644 --- a/backend/src/seeds/transactionLink/index.ts +++ b/backend/src/seeds/transactionLink/index.ts @@ -4,8 +4,7 @@ export const transactionLinks: TransactionLinkInterface[] = [ { email: 'bibi@bloxberg.de', amount: 19.99, - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', - createdAt: new Date(2022, 0, 1), + memo: 'Leider wollte niemand meine Gradidos haben :(', }, { email: 'bibi@bloxberg.de', diff --git a/backend/src/seeds/users/bibi-bloxberg.ts b/backend/src/seeds/users/bibi-bloxberg.ts index 9a40e922b..f78a3af1c 100644 --- a/backend/src/seeds/users/bibi-bloxberg.ts +++ b/backend/src/seeds/users/bibi-bloxberg.ts @@ -9,4 +9,6 @@ export const bibiBloxberg: UserInterface = { emailChecked: true, language: 'de', publisherId: 1234, + // move user createdAt before transaction link + createdAt: new Date(2021, 9, 17), } From a70cfa88ebe7a77dee7af8c49399596d97ef0ca2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:32:13 +0100 Subject: [PATCH 095/226] remove code which was moved to dlt-connector --- backend/src/federation/validateCommunities.ts | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 3b910b313..09217b494 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -87,8 +87,6 @@ export async function validateCommunities(): Promise { logger.error(`Error:`, err) } } - // export communities for gradido dlt node server - await exportCommunitiesToDltNodeServer() } export async function writeJwtKeyPairInHomeCommunity(): Promise { @@ -156,40 +154,3 @@ type CommunityForDltNodeServer = { alias: string folder: string } -async function exportCommunitiesToDltNodeServer(): Promise { - if (!CONFIG.DLT_CONNECTOR) { - return Promise.resolve() - } - const folder = CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER - try { - fs.accessSync(folder, fs.constants.R_OK | fs.constants.W_OK) - } catch (err) { - logger.error(`Error: home folder for DLT Gradido Node Server ${folder} does not exist`) - return - } - - const dbComs = await getReachableCommunities(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER * 4) - const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] - // make sure communityName is unique - const communityName = new Set() - dbComs.forEach((com) => { - if (!com.communityUuid || !com.hieroTopicId) { - return - } - let alias = com.name - if (!alias || communityName.has(alias)) { - alias = com.communityUuid - } - communityName.add(alias) - communitiesForDltNodeServer.push({ - communityId: com.communityUuid, - hieroTopicId: com.hieroTopicId, - alias, - // use only alpha-numeric chars for folder name - folder: alias.replace(/[^a-zA-Z0-9]/g, '_') - }) - }) - const dltNodeServerCommunitiesFile = path.join(folder, 'communities.json') - fs.writeFileSync(dltNodeServerCommunitiesFile, JSON.stringify(communitiesForDltNodeServer, null, 2)) - logger.debug(`Written communitiesForDltNodeServer to ${dltNodeServerCommunitiesFile}`) -} From 495622d55d80ece4e44d3282e0bb873dfd1ac0de Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:32:42 +0100 Subject: [PATCH 096/226] update transaction seed account for structure chance in dlt-connector --- backend/src/apis/dltConnector/index.ts | 2 ++ backend/src/apis/dltConnector/model/AccountIdentifier.ts | 8 +++----- backend/src/apis/dltConnector/model/IdentifierSeed.ts | 9 --------- backend/src/apis/dltConnector/model/TransactionDraft.ts | 5 ++--- 4 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 backend/src/apis/dltConnector/model/IdentifierSeed.ts diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index bce319674..f81d928d1 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -36,8 +36,10 @@ async function checkDltConnectorResult(dltTransaction: DbDltTransaction, clientR logger.debug(e) if (e instanceof Error) { dltTransaction.error = e.message + logger.error('Error from dlt-connector', e) } else if (typeof e === 'string') { dltTransaction.error = e + logger.error('error from dlt-connector', e) } else { throw e } diff --git a/backend/src/apis/dltConnector/model/AccountIdentifier.ts b/backend/src/apis/dltConnector/model/AccountIdentifier.ts index ed1d61e51..3882e8584 100644 --- a/backend/src/apis/dltConnector/model/AccountIdentifier.ts +++ b/backend/src/apis/dltConnector/model/AccountIdentifier.ts @@ -1,15 +1,13 @@ import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' -import { IdentifierSeed } from './IdentifierSeed' - export class AccountIdentifier { communityTopicId: string account?: CommunityAccountIdentifier - seed?: IdentifierSeed // used for deferred transfers + seed?: string // used for deferred transfers - constructor(communityTopicId: string, input: CommunityAccountIdentifier | IdentifierSeed) { + constructor(communityTopicId: string, input: CommunityAccountIdentifier | string) { if (input instanceof CommunityAccountIdentifier) { this.account = input - } else if (input instanceof IdentifierSeed) { + } else { this.seed = input } this.communityTopicId = communityTopicId diff --git a/backend/src/apis/dltConnector/model/IdentifierSeed.ts b/backend/src/apis/dltConnector/model/IdentifierSeed.ts deleted file mode 100644 index 7f7e2fe34..000000000 --- a/backend/src/apis/dltConnector/model/IdentifierSeed.ts +++ /dev/null @@ -1,9 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -export class IdentifierSeed { - seed: string - - constructor(seed: string) { - this.seed = seed - } -} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 5c40da289..fdbce026f 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -12,7 +12,6 @@ import { import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -import { IdentifierSeed } from './IdentifierSeed' import { CODE_VALID_DAYS_DURATION } from '@/graphql/resolver/const/const' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector.model.TransactionDraft`) @@ -94,7 +93,7 @@ export class TransactionDraft { } const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, new CommunityAccountIdentifier(sendingUser.gradidoID)) - draft.linkedUser = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.linkedUser = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER draft.createdAt = transactionLink.createdAt.toISOString() draft.amount = transactionLink.amount.toString() @@ -119,7 +118,7 @@ export class TransactionDraft { throw new Error(`missing topicId for community ${recipientUser.community.id}`) } const draft = new TransactionDraft() - draft.user = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.user = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.linkedUser = new AccountIdentifier(recipientUserTopic, new CommunityAccountIdentifier(recipientUser.gradidoID)) draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER draft.createdAt = createdAt.toISOString() From b63724c4700f692fd5e642afc75df6a266dffda4 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:33:07 +0100 Subject: [PATCH 097/226] remove unneccessary lines --- dlt-connector/log4js-config.json | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 8d865fa26..2956a0816 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -15,19 +15,6 @@ "fileNameSep" : "_", "numBackups" : 30 }, - "dlt.client.HieroClient": { - "type": "dateFile", - "filename": "../logs/dlt-connector/apiversion-%v.log", - "pattern": "yyyy-MM-dd", - "layout": - { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] - %m" - }, - "compress": true, - "keepFileExt" : true, - "fileNameSep" : "_", - "numBackups" : 30 - }, "errorFile": { "type": "dateFile", From f716c92fe93edc4dbd70d3cf018f90c8796b7c19 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:35:06 +0100 Subject: [PATCH 098/226] more infos in error logging --- .../db-v2.7.0_to_blockchain-v3.5/blockchain.ts | 2 +- dlt-connector/src/server/index.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 5a09065a8..38db2af38 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -91,7 +91,7 @@ export async function addTransaction( f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() const deferredTransaction = senderBlockchain.findOne(f) if (!deferredTransaction) { - throw new Error("redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node") + throw new Error(`redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`) } const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() if (!confirmedDeferredTransaction) { diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 191e990d3..1692bacfb 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,5 +1,5 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' -import { Elysia, status, t } from 'elysia' +import { Elysia, status, t, ValidationError } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import * as v from 'valibot' @@ -58,6 +58,14 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) * 🔗 More info: https://elysiajs.com/at-glance.html */ export const appRoutes = new Elysia() + .onError(({ code, error }) => { + if (code === 'VALIDATION' && error instanceof ValidationError) { + logger.debug(JSON.stringify(error.all[0], null, 2)) + logger.error(error.all[0].summary) + return error.all[0].summary + } + return error + }) // check if account exists by user, call example: // GET /isAccountExist/by-user/0.0.21732/408780b2-59b3-402a-94be-56a4f4f4e8ec/0 .get( From f66f33307d3d0ef319b03a256da4057837fcb619 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:36:09 +0100 Subject: [PATCH 099/226] hotfix restart gradido node if it don't get new transaction after 1 second --- .../client/GradidoNode/GradidoNodeProcess.ts | 4 ++ dlt-connector/src/client/hiero/HieroClient.ts | 24 +++++++++++ dlt-connector/src/utils/time.ts | 42 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 dlt-connector/src/utils/time.ts diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index eb2bf6b66..bedbedf38 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -97,6 +97,10 @@ export class GradidoNodeProcess { } } + public getLastStarted(): Date | null { + return this.lastStarted + } + public async exit(): Promise { this.exitCalled = true if (this.proc) { diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 33a208b78..0ed375d62 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -22,6 +22,9 @@ import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { type TopicInfoOutput, topicInfoSchema } from './output.schema' +import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' +import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' +import { printTimeDuration } from '../../utils/time' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds @@ -95,6 +98,27 @@ export class HieroClient { logger.info( `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`, ) + // TODO: fix issue in GradidoNode + // hot fix, when gradido node is running some time, the hiero listener stop working, so we check if our new transaction is received + // after 1 second, else restart GradidoNode + setTimeout(async () => { + const transaction = await GradidoNodeClient.getInstance().getTransaction({ + topic: topicId, + hieroTransactionId: sendResponse.transactionId.toString(), + }) + if (!transaction) { + const process = GradidoNodeProcess.getInstance() + const lastStarted = process.getLastStarted() + if (lastStarted) { + const serverRunTime = printTimeDuration(new Date().getTime() - lastStarted.getTime()) + this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) + await GradidoNodeProcess.getInstance().restart() + } else { + this.logger.error('transaction not found, GradidoNode not running, start it') + GradidoNodeProcess.getInstance().start() + } + } + }, 1000) if (logger.isInfoEnabled()) { // only for logging sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts new file mode 100644 index 000000000..ccbb91c07 --- /dev/null +++ b/dlt-connector/src/utils/time.ts @@ -0,0 +1,42 @@ +/** + * @param {number} time - in minutes + */ +export const getTimeDurationObject = ( + time: number, +): { + hours?: number + minutes: number +} => { + if (time > 60) { + return { + hours: Math.floor(time / 60), + minutes: time % 60, + } + } + return { minutes: time } +} + +/** + * @param startDate + * @param endDate + * @returns duration in minutes + */ +export const durationInMinutesFromDates = (startDate: Date, endDate: Date): number => { + const diff = endDate.getTime() - startDate.getTime() + return Math.floor(diff / (1000 * 60)) +} + +/** + * @param duration in minutes + */ +export const printTimeDuration = (duration: number): string => { + const time = getTimeDurationObject(duration) + const result = time.minutes > 0 ? `${time.minutes} minutes` : '' + if (time.hours) { + return `${time.hours} hours` + (result !== '' ? ` and ${result}` : '') + } + if (result === '') { + return '0 minutes' + } + return result +} From 94ce58a68f33b54d831ca89a73b19c6df8c875f0 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 09:52:01 +0100 Subject: [PATCH 100/226] make restart and exit GradidoNode Process more robust, fix error in ensureCommunitiesAvailable --- .../client/GradidoNode/GradidoNodeProcess.ts | 16 +++++++++++--- .../src/client/GradidoNode/communities.ts | 10 +++++---- dlt-connector/src/client/hiero/HieroClient.ts | 21 ++++++++----------- dlt-connector/src/config/const.ts | 1 + .../sendToHiero/SendToHiero.context.ts | 2 +- dlt-connector/src/utils/time.ts | 4 ++++ 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index bedbedf38..3980bb9f2 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -3,11 +3,13 @@ import { getLogger, Logger } from 'log4js' import { CONFIG } from '../../config' import { GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS, + GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS, GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS, GRADIDO_NODE_RUNTIME_PATH, LOG4JS_BASE_CATEGORY, } from '../../config/const' - +import { Mutex } from 'async-mutex' +import { delay } from '../../utils/time' /** * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. @@ -22,6 +24,7 @@ export class GradidoNodeProcess { private logger: Logger private lastStarted: Date | null = null private exitCalled: boolean = false + private restartMutex: Mutex = new Mutex() private constructor() { // constructor is private to prevent instantiation from outside @@ -55,7 +58,7 @@ export class GradidoNodeProcess { USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, }, - onExit(proc, exitCode, signalCode, error) { + onExit(_proc, exitCode, signalCode, error) { logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`) if (error) { logger.error(`GradidoNodeProcess exit error: ${error}`) @@ -69,7 +72,6 @@ export class GradidoNodeProcess { }) }*/ } - logger.debug(`ressource usage: ${JSON.stringify(proc?.resourceUsage(), null, 2)}`) const gradidoNodeProcess = GradidoNodeProcess.getInstance() gradidoNodeProcess.proc = null if ( @@ -90,11 +92,16 @@ export class GradidoNodeProcess { } public async restart() { + const release = await this.restartMutex.acquire() + try { if (this.proc) { await this.exit() this.exitCalled = false this.start() } + } finally { + release() + } } public getLastStarted(): Date | null { @@ -104,6 +111,9 @@ export class GradidoNodeProcess { public async exit(): Promise { this.exitCalled = true if (this.proc) { + if (this.lastStarted && Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS) { + await delay(GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - Date.now() - this.lastStarted.getTime()) + } this.proc.kill('SIGTERM') const timeout = setTimeout(() => { this.logger.warn( diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts index d25ed4dd4..76384f847 100644 --- a/dlt-connector/src/client/GradidoNode/communities.ts +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -27,7 +27,8 @@ export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]): CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, GRADIDO_NODE_HOME_FOLDER_NAME, ) - if (!checkCommunityAvailable(communityTopicIds, homeFolder)) { + const communityTopicIdsSet = new Set(communityTopicIds) + if (!checkCommunityAvailable(communityTopicIdsSet, homeFolder)) { await exportCommunities(homeFolder, BackendClient.getInstance()) return GradidoNodeProcess.getInstance().restart() } @@ -65,7 +66,7 @@ export async function exportCommunities(homeFolder: string, client: BackendClien logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`) } -export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder: string): boolean { +export function checkCommunityAvailable(communityTopicIds: Set, homeFolder: string): boolean { const communitiesPath = path.join(homeFolder, 'communities.json') if (!checkFileExist(communitiesPath)) { return false @@ -73,12 +74,13 @@ export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder const communities = JSON.parse(fs.readFileSync(communitiesPath, 'utf-8')) let foundCount = 0 for (const community of communities) { - if (communityTopicIds.includes(community.hieroTopicId)) { + if (communityTopicIds.has(community.hieroTopicId)) { foundCount++ - if (foundCount >= communityTopicIds.length) { + if (foundCount >= communityTopicIds.size) { return true } } } + logger.debug(`community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`) return false } diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 0ed375d62..f81da11c5 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -15,7 +15,7 @@ import { TransactionId, Wallet, } from '@hashgraph/sdk' -import { GradidoTransaction } from 'gradido-blockchain-js' +import { GradidoTransaction, Profiler } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' import * as v from 'valibot' import { CONFIG } from '../../config' @@ -24,8 +24,7 @@ import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { type TopicInfoOutput, topicInfoSchema } from './output.schema' import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' -import { printTimeDuration } from '../../utils/time' - +import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds export const MAX_AUTORENEW_PERIOD = 8000001 // seconds @@ -75,7 +74,7 @@ export class HieroClient { topicId: HieroId, transaction: GradidoTransaction, ): Promise { - const startTime = new Date() + const timeUsed = new Profiler() this.transactionInternNr++ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) logger.addContext('trNr', this.transactionInternNr) @@ -96,11 +95,11 @@ export class HieroClient { .then(async (signedHieroTransaction) => { const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) logger.info( - `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`, + `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}, timeUsed: ${timeUsed.string()}`, ) // TODO: fix issue in GradidoNode // hot fix, when gradido node is running some time, the hiero listener stop working, so we check if our new transaction is received - // after 1 second, else restart GradidoNode + // after 10 seconds, else restart GradidoNode setTimeout(async () => { const transaction = await GradidoNodeClient.getInstance().getTransaction({ topic: topicId, @@ -110,7 +109,7 @@ export class HieroClient { const process = GradidoNodeProcess.getInstance() const lastStarted = process.getLastStarted() if (lastStarted) { - const serverRunTime = printTimeDuration(new Date().getTime() - lastStarted.getTime()) + const serverRunTime = printTimeDuration(durationInMinutesFromDates(lastStarted, new Date())) this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) await GradidoNodeProcess.getInstance().restart() } else { @@ -118,7 +117,7 @@ export class HieroClient { GradidoNodeProcess.getInstance().start() } } - }, 1000) + }, 10000) if (logger.isInfoEnabled()) { // only for logging sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { @@ -127,9 +126,8 @@ export class HieroClient { // only for logging sendResponse.getRecordWithSigner(this.wallet).then((record) => { logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - const localEndTime = new Date() logger.info( - `HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`, + `HieroClient.sendMessage used time (full process): ${timeUsed.string()}`, ) }) } @@ -141,8 +139,7 @@ export class HieroClient { this.pendingPromises.splice(pendingPromiseIndex, 1) }), ) - const endTime = new Date() - logger.info(`HieroClient.sendMessage used time: ${endTime.getTime() - startTime.getTime()}ms`) + logger.debug(`create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`) return hieroTransaction.transactionId } diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index dc4b0177c..5657f65ee 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -16,6 +16,7 @@ export const GRADIDO_NODE_RUNTIME_PATH = path.join( ) // if last start was less than this time, do not restart export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30 +export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS = 1000 * 2 export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 10000 // currently hard coded in gradido node, update in future export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido' diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 5ef946ec9..269bccada 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -104,7 +104,7 @@ async function sendViaHiero( if (!transactionId) { throw new Error('missing transaction id from hiero') } - logger.info('transmitted Gradido Transaction to Hiero', { + logger.debug('give Gradido Transaction to Hiero Client', { transactionId: transactionId.toString(), }) return v.parse(hieroTransactionIdStringSchema, transactionId.toString()) diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts index ccbb91c07..4f69ebd98 100644 --- a/dlt-connector/src/utils/time.ts +++ b/dlt-connector/src/utils/time.ts @@ -1,3 +1,5 @@ +import { promisify } from 'node:util' + /** * @param {number} time - in minutes */ @@ -40,3 +42,5 @@ export const printTimeDuration = (duration: number): string => { } return result } + +export const delay = promisify(setTimeout) \ No newline at end of file From a8e7a26f8d5b817c69ea21c7cbed01d81216bbf1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 11:13:39 +0100 Subject: [PATCH 101/226] make sure seeded links delete one second after createdAt --- backend/src/seeds/factory/transactionLink.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index a71a20955..80384025f 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -39,7 +39,7 @@ export const transactionLinkFactory = async ( } if (transactionLink.deletedAt) { - dbTransactionLink.deletedAt = new Date() + dbTransactionLink.deletedAt = new Date(dbTransactionLink.createdAt.getTime() + 1000) await dbTransactionLink.save() } } From 7912c2517cc7e932d89972aafa481c482895500c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:00:57 +0100 Subject: [PATCH 102/226] update versions of gradido node and gradido-blockchain-js --- dlt-connector/bun.lock | 4 ++-- dlt-connector/package.json | 2 +- dlt-connector/src/config/schema.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 6f6fd84d4..fb882d0b9 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -4,7 +4,7 @@ "": { "name": "dlt-connector", "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf", }, "devDependencies": { "@biomejs/biome": "2.0.0", @@ -569,7 +569,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#8a0c7b0", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-8a0c7b0"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#f265dbb", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-f265dbb"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index c4c6f1099..57302b3ab 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -18,7 +18,7 @@ "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js" + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf" }, "devDependencies": { "@biomejs/biome": "2.0.0", diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 9131a3132..09eca49b2 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -84,7 +84,7 @@ export const configSchema = v.object({ v.string('The version of the DLT node server, for example: 0.9.0'), v.regex(/^\d+\.\d+\.\d+$/), ), - '0.9.0', + '0.9.1', ), DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( v.string('The home folder for the gradido dlt node server'), From 56e4d6387c096ebe786efef1c3c7f2dbf3a5d912 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:01:54 +0100 Subject: [PATCH 103/226] precision fixes for dlt migration and live transactions --- backend/src/apis/dltConnector/model/TransactionDraft.ts | 8 ++++++-- .../migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts | 1 + .../migrations/db-v2.7.0_to_blockchain-v3.5/database.ts | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index fdbce026f..0fae08297 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -91,11 +91,13 @@ export class TransactionDraft { if (!senderUserTopic) { throw new Error(`missing topicId for community ${sendingUser.community.id}`) } + const createdAtOnlySeconds = transactionLink.createdAt + createdAtOnlySeconds.setMilliseconds(0) const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, new CommunityAccountIdentifier(sendingUser.gradidoID)) draft.linkedUser = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER - draft.createdAt = transactionLink.createdAt.toISOString() + draft.createdAt = createdAtOnlySeconds.toISOString() draft.amount = transactionLink.amount.toString() draft.memo = transactionLink.memo draft.timeoutDuration = CODE_VALID_DAYS_DURATION * 24 * 60 * 60 @@ -117,11 +119,13 @@ export class TransactionDraft { if (!recipientUserTopic) { throw new Error(`missing topicId for community ${recipientUser.community.id}`) } + const createdAtOnlySeconds = createdAt + createdAtOnlySeconds.setMilliseconds(0) const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.linkedUser = new AccountIdentifier(recipientUserTopic, new CommunityAccountIdentifier(recipientUser.gradidoID)) draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER - draft.createdAt = createdAt.toISOString() + draft.createdAt = createdAtOnlySeconds.toISOString() draft.amount = amount return draft } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 38db2af38..273451e14 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -26,6 +26,7 @@ export const defaultHieroAccount = new HieroAccountId(0, 0, 2) function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { const transaction = builder.build() + // TOD: use actual transaction id if exist in dlt_transactions table const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index f66536c0a..459996642 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -3,7 +3,7 @@ import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { getLogger } from 'log4js' import { MySql2Database } from 'drizzle-orm/mysql2' import { communitiesTable, transactionLinksTable, transactionsTable, usersTable } from './drizzle.schema' -import { asc, sql, eq, isNotNull } from 'drizzle-orm' +import { asc, sql, eq, isNotNull, inArray } from 'drizzle-orm' import { alias } from 'drizzle-orm/mysql-core' import { GradidoUnit } from 'gradido-blockchain-js' import { @@ -70,6 +70,7 @@ export async function loadTransactions(db: MySql2Database, offset: number, count transactionLink: transactionLinksTable, }) .from(transactionsTable) + .where(inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE])) .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) @@ -102,6 +103,7 @@ export async function loadTransactions(db: MySql2Database, offset: number, count }) } catch (e) { if (e instanceof v.ValiError) { + logger.error(`table row: ${JSON.stringify(row, null, 2)}`) logger.error(v.flatten(e.issues)) } throw e From a7c3bab20e4b05a9539fb0947438626b6e84b596 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:07:24 +0100 Subject: [PATCH 104/226] fix lint --- dlt-connector/src/bootstrap/init.ts | 2 +- .../client/GradidoNode/GradidoNodeProcess.ts | 23 ++- .../src/client/GradidoNode/communities.ts | 9 +- dlt-connector/src/client/hiero/HieroClient.ts | 22 ++- dlt-connector/src/config/schema.ts | 10 +- .../src/data/KeyPairIdentifier.logic.ts | 4 +- .../resolveKeyPair/ResolveKeyPair.context.ts | 2 +- .../RedeemDeferredTransferTransaction.role.ts | 11 +- .../sendToHiero/SendToHiero.context.ts | 15 +- .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 27 ++- .../binaryExport.ts | 53 ++++-- .../blockchain.ts | 152 +++++++++++---- .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 24 +-- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 65 +++++-- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 174 +++++++++++------- .../drizzle.schema.ts | 98 +++++----- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 14 +- .../syncDbWithBlockchain/AbstractSync.role.ts | 17 +- .../DeletedTransactionLinksSync.role.ts | 4 +- .../TransactionLinksSync.role.ts | 7 +- .../TransactionsSync.role.ts | 23 ++- .../syncDbWithBlockchain/UsersSync.role.ts | 9 +- .../syncDbWithBlockchain.context.ts | 19 +- .../db-v2.7.0_to_blockchain-v3.5/keyPair.ts | 64 ++++--- .../db-v2.7.0_to_blockchain-v3.5/utils.ts | 2 +- .../valibot.schema.ts | 22 ++- .../src/schemas/typeConverter.schema.ts | 8 +- dlt-connector/src/utils/time.ts | 2 +- 28 files changed, 549 insertions(+), 333 deletions(-) diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index e0289db57..13b77783c 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -39,7 +39,7 @@ export async function checkHomeCommunity( // wait for backend server await isPortOpenRetry(backend.url) // ask backend for home community - let homeCommunity = await backend.getHomeCommunityDraft() + let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.hieroTopicId) { const topicId = await hiero.createTopic(homeCommunity.name) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index 3980bb9f2..0eae2f37e 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -1,3 +1,4 @@ +import { Mutex } from 'async-mutex' import { Subprocess, spawn } from 'bun' import { getLogger, Logger } from 'log4js' import { CONFIG } from '../../config' @@ -8,7 +9,6 @@ import { GRADIDO_NODE_RUNTIME_PATH, LOG4JS_BASE_CATEGORY, } from '../../config/const' -import { Mutex } from 'async-mutex' import { delay } from '../../utils/time' /** * A Singleton class defines the `getInstance` method that lets clients access @@ -94,11 +94,11 @@ export class GradidoNodeProcess { public async restart() { const release = await this.restartMutex.acquire() try { - if (this.proc) { - await this.exit() - this.exitCalled = false - this.start() - } + if (this.proc) { + await this.exit() + this.exitCalled = false + this.start() + } } finally { release() } @@ -111,8 +111,15 @@ export class GradidoNodeProcess { public async exit(): Promise { this.exitCalled = true if (this.proc) { - if (this.lastStarted && Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS) { - await delay(GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - Date.now() - this.lastStarted.getTime()) + if ( + this.lastStarted && + Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS + ) { + await delay( + GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - + Date.now() - + this.lastStarted.getTime(), + ) } this.proc.kill('SIGTERM') const timeout = setTimeout(() => { diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts index 76384f847..a418255f7 100644 --- a/dlt-connector/src/client/GradidoNode/communities.ts +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -66,7 +66,10 @@ export async function exportCommunities(homeFolder: string, client: BackendClien logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`) } -export function checkCommunityAvailable(communityTopicIds: Set, homeFolder: string): boolean { +export function checkCommunityAvailable( + communityTopicIds: Set, + homeFolder: string, +): boolean { const communitiesPath = path.join(homeFolder, 'communities.json') if (!checkFileExist(communitiesPath)) { return false @@ -81,6 +84,8 @@ export function checkCommunityAvailable(communityTopicIds: Set, homeFol } } } - logger.debug(`community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`) + logger.debug( + `community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`, + ) return false } diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index f81da11c5..c32c4cbd7 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -21,10 +21,10 @@ import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import { type TopicInfoOutput, topicInfoSchema } from './output.schema' +import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' -import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' +import { type TopicInfoOutput, topicInfoSchema } from './output.schema' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds export const MAX_AUTORENEW_PERIOD = 8000001 // seconds @@ -109,9 +109,13 @@ export class HieroClient { const process = GradidoNodeProcess.getInstance() const lastStarted = process.getLastStarted() if (lastStarted) { - const serverRunTime = printTimeDuration(durationInMinutesFromDates(lastStarted, new Date())) - this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) - await GradidoNodeProcess.getInstance().restart() + const serverRunTime = printTimeDuration( + durationInMinutesFromDates(lastStarted, new Date()), + ) + this.logger.error( + `transaction not found, restart GradidoNode after ${serverRunTime}`, + ) + await GradidoNodeProcess.getInstance().restart() } else { this.logger.error('transaction not found, GradidoNode not running, start it') GradidoNodeProcess.getInstance().start() @@ -126,9 +130,7 @@ export class HieroClient { // only for logging sendResponse.getRecordWithSigner(this.wallet).then((record) => { logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - logger.info( - `HieroClient.sendMessage used time (full process): ${timeUsed.string()}`, - ) + logger.info(`HieroClient.sendMessage used time (full process): ${timeUsed.string()}`) }) } }) @@ -139,7 +141,9 @@ export class HieroClient { this.pendingPromises.splice(pendingPromiseIndex, 1) }), ) - logger.debug(`create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`) + logger.debug( + `create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`, + ) return hieroTransaction.transactionId } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 09eca49b2..45ef83831 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -99,10 +99,7 @@ export const configSchema = v.object({ ), '4000', ), - MYSQL_HOST: v.optional( - v.string('The host of the database'), - 'localhost', - ), + MYSQL_HOST: v.optional(v.string('The host of the database'), 'localhost'), MYSQL_PORT: v.optional( v.pipe( v.string('The port of the database'), @@ -136,8 +133,5 @@ export const configSchema = v.object({ ), '', ), - MYSQL_DATABASE: v.optional( - v.string('The name of the database'), - 'gradido_community', - ), + MYSQL_DATABASE: v.optional(v.string('The name of the database'), 'gradido_community'), }) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 61f4d3cfb..3b6b71c6e 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -107,7 +107,9 @@ export class KeyPairIdentifierLogic { ) } const resultString = - this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + accountNr.toString() + this.identifier.communityTopicId + + this.identifier.account.userUuid.replace(/-/g, '') + + accountNr.toString() return new MemoryBlock(resultString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 21187602b..406463c4c 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -32,7 +32,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' */ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { const cache = KeyPairCacheManager.getInstance() - + return await cache.getKeyPair( input.getKey(), // function is called from cache manager, if key isn't currently cached diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 2f51f8f21..4615a4707 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,4 +1,9 @@ -import { ConfirmedTransaction, GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { + ConfirmedTransaction, + GradidoTransactionBuilder, + GradidoTransfer, + TransferAmount, +} from 'gradido-blockchain-js' import * as v from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { @@ -42,7 +47,9 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo if (!senderPublicKey) { throw new Error("redeem deferred transfer: couldn't calculate sender public key") } - const deferredTransferBody = this.parentDeferredTransaction.getGradidoTransaction()?.getTransactionBody() + const deferredTransferBody = this.parentDeferredTransaction + .getGradidoTransaction() + ?.getTransactionBody() if (!deferredTransferBody) { throw new Error( "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 269bccada..622addb28 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -6,9 +6,9 @@ import { ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import * as v from 'valibot' import { ensureCommunitiesAvailable } from '../../client/GradidoNode/communities' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { InputTransactionType } from '../../data/InputTransactionType.enum' @@ -25,6 +25,7 @@ import { identifierSeedSchema, } from '../../schemas/typeGuard.schema' import { isTopicStillOpen } from '../../utils/hiero' +import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' @@ -32,7 +33,6 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' -import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) @@ -146,9 +146,11 @@ async function chooseCorrectRole( return new RegisterAddressTransactionRole(transaction) case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: return new DeferredTransferTransactionRole(transaction) - case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: { // load deferred transfer transaction from gradido node - const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedKeyPairRole = new LinkedTransactionKeyPairRole( + v.parse(identifierSeedSchema, transaction.user.seed), + ) const seedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() if (!seedPublicKey) { throw new Error("redeem deferred transfer: couldn't generate seed public key") @@ -158,9 +160,12 @@ async function chooseCorrectRole( seedPublicKey.convertToHex(), ) if (!transactions || transactions.length !== 1) { - throw new Error("redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node") + throw new Error( + "redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node", + ) } return new RedeemDeferredTransferTransactionRole(transaction, transactions[0]) + } default: throw new Error('not supported transaction type: ' + transaction.type) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index 9eb549a30..58400a615 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,17 +1,15 @@ +import { heapStats } from 'bun:jsc' import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' -import mysql from 'mysql2/promise' import { Filter, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' - -import { Uuidv4 } from '../../schemas/typeGuard.schema' - -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import mysql from 'mysql2/promise' import { loadConfig } from '../../bootstrap/init' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { heapStats } from 'bun:jsc' -import { CommunityContext } from './valibot.schema' +import { Uuidv4 } from '../../schemas/typeGuard.schema' import { bytesToMbyte } from './utils' +import { CommunityContext } from './valibot.schema' export class Context { public logger: Logger @@ -36,12 +34,12 @@ export class Context { user: CONFIG.MYSQL_USER, password: CONFIG.MYSQL_PASSWORD, database: CONFIG.MYSQL_DATABASE, - port: CONFIG.MYSQL_PORT + port: CONFIG.MYSQL_PORT, }) return new Context( getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), - drizzle({ client: connection }), - KeyPairCacheManager.getInstance() + drizzle({ client: connection }), + KeyPairCacheManager.getInstance(), ) } @@ -57,18 +55,18 @@ export class Context { this.logger.info(`${this.timeUsed.string()} for synchronizing to blockchain`) const runtimeStats = heapStats() this.logger.info( - `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte`, ) } logBlogchain(communityUuid: Uuidv4) { const communityContext = this.getCommunityContextByUuid(communityUuid) - const f = new Filter() + const f = new Filter() f.pagination.size = 0 f.searchDirection = SearchDirection_ASC - + const transactions = communityContext.blockchain.findAll(f) - for(let i = 0; i < transactions.size(); i++) { + for (let i = 0; i < transactions.size(); i++) { const transaction = transactions.get(i) const confirmedTransaction = transaction?.getConfirmedTransaction() this.logger.info(confirmedTransaction?.toJson(true)) @@ -76,5 +74,4 @@ export class Context { } // TODO: move into utils - } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts index 74181f34f..474df61b8 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -1,21 +1,30 @@ -import { ConfirmedTransaction, Filter, InteractionSerialize, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' -import path from 'node:path' -import { CONFIG } from '../../config' import fs from 'node:fs' -import { bytesToKbyte } from './utils' -import { calculateOneHashStep } from './utils' +import path from 'node:path' +import { + ConfirmedTransaction, + Filter, + InteractionSerialize, + Profiler, + SearchDirection_ASC, +} from 'gradido-blockchain-js' +import { CONFIG } from '../../config' import { Context } from './Context' +import { bytesToKbyte, calculateOneHashStep } from './utils' import { CommunityContext } from './valibot.schema' export function exportAllCommunities(context: Context, batchSize: number) { const timeUsed = new Profiler() - for(const communityContext of context.communities.values()) { + for (const communityContext of context.communities.values()) { exportCommunity(communityContext, context, batchSize) } context.logger.info(`time used for exporting communities to binary file: ${timeUsed.string()}`) } -export function exportCommunity(communityContext: CommunityContext, context: Context, batchSize: number) { +export function exportCommunity( + communityContext: CommunityContext, + context: Context, + batchSize: number, +) { // write as binary file for GradidoNode const f = new Filter() f.pagination.size = batchSize @@ -28,7 +37,7 @@ export function exportCommunity(communityContext: CommunityContext, context: Con do { const transactions = communityContext.blockchain.findAll(f) lastTransactionCount = transactions.size() - + for (let i = 0; i < lastTransactionCount; i++) { const confirmedTransaction = transactions.get(i)?.getConfirmedTransaction() const transactionNr = f.pagination.page * batchSize + i @@ -39,22 +48,30 @@ export function exportCommunity(communityContext: CommunityContext, context: Con } f.pagination.page++ } while (lastTransactionCount === batchSize) - + fs.appendFileSync(binFilePath, hash!) - context.logger.info(`binary file for community ${communityContext.communityId} written to ${binFilePath}`) context.logger.info( - `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte` + `binary file for community ${communityContext.communityId} written to ${binFilePath}`, + ) + context.logger.info( + `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte`, ) } -function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buffer, binFilePath: string): Buffer { - const sizeBuffer = Buffer.alloc(2) +function exportTransaction( + confirmedTransaction: ConfirmedTransaction, + hash: Buffer, + binFilePath: string, +): Buffer { + const sizeBuffer = Buffer.alloc(2) const interactionSerialize = new InteractionSerialize(confirmedTransaction) const binBlock = interactionSerialize.run() if (!binBlock) { - throw new Error(`invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`) + throw new Error( + `invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`, + ) } - + hash = calculateOneHashStep(hash, binBlock.data()) sizeBuffer.writeUInt16LE(binBlock.size(), 0) fs.appendFileSync(binFilePath, sizeBuffer) @@ -64,13 +81,13 @@ function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buf function prepareFolder(communityContext: CommunityContext): string { const binFileFolder = path.join( - CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, '.gradido', communityContext.folder, ) const binFilePath = path.join(binFileFolder, 'blk00000001.dat') // make sure we work with a clean folder, rm beforehand with all content fs.rmSync(binFileFolder, { recursive: true }) - fs.mkdirSync(binFileFolder, { recursive: true }) + fs.mkdirSync(binFileFolder, { recursive: true }) return binFilePath -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 273451e14..fd89d5ea0 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -1,37 +1,47 @@ -import { - InMemoryBlockchain, - GradidoTransactionBuilder, - Timestamp, - HieroTransactionId, - HieroAccountId, - InteractionSerialize, +import { Filter, + GradidoTransactionBuilder, + HieroAccountId, + HieroTransactionId, + InMemoryBlockchain, + InteractionSerialize, + Timestamp, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' -import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' -import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import * as v from 'valibot' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { Community, Transaction } from '../../schemas/transaction.schema' -import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' -import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' -import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' import { InputTransactionType } from '../../data/InputTransactionType.enum' import { LinkedTransactionKeyPairRole } from '../../interactions/resolveKeyPair/LinkedTransactionKeyPair.role' +import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' +import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' +import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' +import { Community, Transaction } from '../../schemas/transaction.schema' import { identifierSeedSchema } from '../../schemas/typeGuard.schema' -import * as v from 'valibot' -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) +const logger = getLogger( + `${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`, +) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) -function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { +function addToBlockchain( + builder: GradidoTransactionBuilder, + blockchain: InMemoryBlockchain, + createdAtTimestamp: Timestamp, +): boolean { const transaction = builder.build() // TOD: use actual transaction id if exist in dlt_transactions table const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) try { - const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + const result = blockchain.createAndAddConfirmedTransaction( + transaction, + interactionSerialize.run(), + createdAtTimestamp, + ) return result } catch (error) { logger.error(`Transaction ${transaction.toJson(true)} not added: ${error}`) @@ -39,68 +49,130 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor } } -export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { +export async function addCommunityRootTransaction( + blockchain: InMemoryBlockchain, + community: Community, +): Promise { const communityRootTransactionRole = new CommunityRootTransactionRole(community) - if(addToBlockchain(await communityRootTransactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(community.creationDate))) { + if ( + addToBlockchain( + await communityRootTransactionRole.getGradidoTransactionBuilder(), + blockchain, + new Timestamp(community.creationDate), + ) + ) { logger.info(`Community Root Transaction added`) } else { throw new Error(`Community Root Transaction not added`) } } -export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { +export async function addRegisterAddressTransaction( + blockchain: InMemoryBlockchain, + transaction: Transaction, +): Promise { const registerAddressRole = new RegisterAddressTransactionRole(transaction) - if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { - logger.debug(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + if ( + addToBlockchain( + await registerAddressRole.getGradidoTransactionBuilder(), + blockchain, + new Timestamp(transaction.createdAt), + ) + ) { + logger.debug( + `Register Address Transaction added for user ${transaction.user.account!.userUuid}`, + ) } else { - throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Register Address Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } export async function addTransaction( senderBlockchain: InMemoryBlockchain, _recipientBlockchain: InMemoryBlockchain, - transaction: Transaction + transaction: Transaction, ): Promise { const createdAtTimestamp = new Timestamp(transaction.createdAt) if (transaction.type === InputTransactionType.GRADIDO_CREATION) { const creationTransactionRole = new CreationTransactionRole(transaction) - if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + if ( + addToBlockchain( + await creationTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { - throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) - } + throw new Error( + `Creation Transaction not added for user ${transaction.user.account!.userUuid}`, + ) + } } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction - if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + if ( + addToBlockchain( + await transferTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { - throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Transfer Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } else if (transaction.type === InputTransactionType.GRADIDO_DEFERRED_TRANSFER) { const transferTransactionRole = new DeferredTransferTransactionRole(transaction) - if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + if ( + addToBlockchain( + await transferTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { + logger.debug( + `Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`, + ) } else { - - throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { - const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedKeyPairRole = new LinkedTransactionKeyPairRole( + v.parse(identifierSeedSchema, transaction.user.seed), + ) const f = new Filter() f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() const deferredTransaction = senderBlockchain.findOne(f) if (!deferredTransaction) { - throw new Error(`redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`) + throw new Error( + `redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`, + ) } const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() if (!confirmedDeferredTransaction) { - throw new Error("redeem deferred transfer: invalid TransactionEntry") + throw new Error('redeem deferred transfer: invalid TransactionEntry') } - const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction, confirmedDeferredTransaction) - const involvedUser = transaction.user.account ? transaction.user.account.userUuid : transaction.linkedUser?.account?.userUuid - if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole( + transaction, + confirmedDeferredTransaction, + ) + const involvedUser = transaction.user.account + ? transaction.user.account.userUuid + : transaction.linkedUser?.account?.userUuid + if ( + addToBlockchain( + await redeemTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Redeem Deferred Transfer Transaction added for user ${involvedUser}`) } else { throw new Error(`Redeem Deferred Transfer Transaction not added for user ${involvedUser}`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index ef792e8d6..c613eb655 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -1,11 +1,11 @@ -import { Context } from './Context' -import { loadCommunities } from './database' -import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import * as v from 'valibot' import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' -import { generateKeyPairCommunity } from './keyPair' -import { communityDbToCommunity } from './convert' +import * as v from 'valibot' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { addCommunityRootTransaction } from './blockchain' +import { Context } from './Context' +import { communityDbToCommunity } from './convert' +import { loadCommunities } from './database' +import { generateKeyPairCommunity } from './keyPair' import { CommunityContext } from './valibot.schema' export async function bootstrap(): Promise { @@ -18,18 +18,20 @@ async function bootstrapCommunities(context: Context): Promise() const communitiesDb = await loadCommunities(context.db) const topicIds = new Set() - + for (const communityDb of communitiesDb) { - const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain(communityDb.uniqueAlias) + const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain( + communityDb.uniqueAlias, + ) if (!blockchain) { throw new Error(`Couldn't create Blockchain for community ${communityDb.communityUuid}`) } context.logger.info(`Blockchain for community '${communityDb.uniqueAlias}' created`) // make sure topic id is unique - let topicId: HieroId + let topicId: HieroId do { topicId = v.parse(hieroIdSchema, '0.0.' + Math.floor(Math.random() * 10000)) - } while(topicIds.has(topicId)) + } while (topicIds.has(topicId)) topicIds.add(topicId) communities.set(communityDb.communityUuid, { @@ -38,7 +40,7 @@ async function bootstrapCommunities(context: Context): Promise { - const result = await db.select({ - foreign: communitiesTable.foreign, - communityUuid: communitiesTable.communityUuid, - name: communitiesTable.name, - creationDate: communitiesTable.creationDate, - userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, - }) - .from(communitiesTable) - .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) - .where(isNotNull(communitiesTable.communityUuid)) - .groupBy(communitiesTable.communityUuid) + const result = await db + .select({ + foreign: communitiesTable.foreign, + communityUuid: communitiesTable.communityUuid, + name: communitiesTable.name, + creationDate: communitiesTable.creationDate, + userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, + }) + .from(communitiesTable) + .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) + .where(isNotNull(communitiesTable.communityUuid)) + .groupBy(communitiesTable.communityUuid) const communityNames = new Set() return result.map((row: any) => { @@ -49,33 +57,50 @@ export async function loadCommunities(db: MySql2Database): Promise { - const result = await db.select() - .from(usersTable) - .orderBy(asc(usersTable.createdAt)) - .limit(count).offset(offset) +export async function loadUsers( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(usersTable) + .orderBy(asc(usersTable.createdAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) } -export async function loadTransactions(db: MySql2Database, offset: number, count: number): Promise { +export async function loadTransactions( + db: MySql2Database, + offset: number, + count: number, +): Promise { const linkedUsers = alias(usersTable, 'linkedUser') - - const result = await db.select({ - transaction: transactionsTable, - user: usersTable, - linkedUser: linkedUsers, - transactionLink: transactionLinksTable, - }) - .from(transactionsTable) - .where(inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE])) - .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) - .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) - .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) - .orderBy(asc(transactionsTable.balanceDate)) - .limit(count).offset(offset) + + const result = await db + .select({ + transaction: transactionsTable, + user: usersTable, + linkedUser: linkedUsers, + transactionLink: transactionLinksTable, + }) + .from(transactionsTable) + .where( + inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE]), + ) + .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) + .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) + .leftJoin( + transactionLinksTable, + eq(transactionsTable.transactionLinkId, transactionLinksTable.id), + ) + .orderBy(asc(transactionsTable.balanceDate)) + .limit(count) + .offset(offset) return result.map((row: any) => { // console.log(row) @@ -83,13 +108,14 @@ export async function loadTransactions(db: MySql2Database, offset: number, count const userCreatedAt = new Date(row.user.createdAt) const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) const balanceDate = new Date(row.transaction.balanceDate) - if (userCreatedAt.getTime() > balanceDate.getTime() || - linkedUserCreatedAd.getTime() > balanceDate.getTime() - ){ + if ( + userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ) { logger.error(`table row: `, row) throw new Error('at least one user was created after transaction balance date, logic error!') } - + let amount = GradidoUnit.fromString(row.transaction.amount) if (row.transaction.typeId === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) @@ -111,12 +137,18 @@ export async function loadTransactions(db: MySql2Database, offset: number, count }) } -export async function loadTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { - const result = await db.select() - .from(transactionLinksTable) - .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) - .orderBy(asc(transactionLinksTable.createdAt)) - .limit(count).offset(offset) +export async function loadTransactionLinks( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .orderBy(asc(transactionLinksTable.createdAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(transactionLinkDbSchema, { @@ -126,23 +158,29 @@ export async function loadTransactionLinks(db: MySql2Database, offset: number, c }) } -export async function loadDeletedTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { - const result = await db.select() - .from(transactionLinksTable) - .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) - .where(isNotNull(transactionLinksTable.deletedAt)) - .orderBy(asc(transactionLinksTable.deletedAt)) - .limit(count).offset(offset) +export async function loadDeletedTransactionLinks( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .where(isNotNull(transactionLinksTable.deletedAt)) + .orderBy(asc(transactionLinksTable.deletedAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(transactionDbSchema, { typeId: TransactionTypeId.RECEIVE, - amount: row.transaction_links.amount, + amount: row.transaction_links.amount, balanceDate: new Date(row.transaction_links.deletedAt), memo: row.transaction_links.memo, transactionLinkCode: row.transaction_links.code, user: row.users, - linkedUser: row.users + linkedUser: row.users, }) }) -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts index f96b71bfe..59cc6573c 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -1,50 +1,66 @@ - -import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' import { sql } from 'drizzle-orm' +import { + char, + datetime, + decimal, + index, + int, + mysqlTable, + tinyint, + unique, + varchar, +} from 'drizzle-orm/mysql-core' // use only fields needed in the migration, after update the rest of the project, import database instead -export const communitiesTable = mysqlTable('communities', { - foreign: tinyint().default(1).notNull(), - communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), - name: varchar({ length: 40 }).default(sql`NULL`), - creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), -}, -(table) => [ - unique('uuid_key').on(table.communityUuid), -]) +export const communitiesTable = mysqlTable( + 'communities', + { + foreign: tinyint().default(1).notNull(), + communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), + name: varchar({ length: 40 }).default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + }, + (table) => [unique('uuid_key').on(table.communityUuid)], +) -export const usersTable = mysqlTable('users', { - id: int().autoincrement().notNull(), - gradidoId: char('gradido_id', { length: 36 }).notNull(), - communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), - createdAt: datetime('created_at', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), -}, -(table) => [ - unique('uuid_key').on(table.gradidoId, table.communityUuid), -]) +export const usersTable = mysqlTable( + 'users', + { + id: int().autoincrement().notNull(), + gradidoId: char('gradido_id', { length: 36 }).notNull(), + communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), + createdAt: datetime('created_at', { mode: 'string', fsp: 3 }) + .default(sql`current_timestamp(3)`) + .notNull(), + }, + (table) => [unique('uuid_key').on(table.gradidoId, table.communityUuid)], +) -export const transactionsTable = mysqlTable('transactions', { - id: int().autoincrement().notNull(), - typeId: int('type_id').default(sql`NULL`), - transactionLinkId: int('transaction_link_id').default(sql`NULL`), - amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), - balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), - memo: varchar({ length: 255 }).notNull(), - creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), - userId: int('user_id').notNull(), - linkedUserId: int('linked_user_id').default(sql`NULL`), -}, -(table) => [ - index('user_id').on(table.userId), -]) +export const transactionsTable = mysqlTable( + 'transactions', + { + id: int().autoincrement().notNull(), + typeId: int('type_id').default(sql`NULL`), + transactionLinkId: int('transaction_link_id').default(sql`NULL`), + amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), + balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }) + .default(sql`current_timestamp(3)`) + .notNull(), + memo: varchar({ length: 255 }).notNull(), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int('user_id').notNull(), + linkedUserId: int('linked_user_id').default(sql`NULL`), + }, + (table) => [index('user_id').on(table.userId)], +) export const transactionLinksTable = mysqlTable('transaction_links', { - id: int().autoincrement().notNull(), + id: int().autoincrement().notNull(), userId: int().notNull(), - amount: decimal({ precision: 40, scale: 20 }).notNull(), - memo: varchar({ length: 255 }).notNull(), - code: varchar({ length: 24 }).notNull(), - createdAt: datetime({ mode: 'string'}).notNull(), - deletedAt: datetime({ mode: 'string'}).default(sql`NULL`), - validUntil: datetime({ mode: 'string'}).notNull(), + amount: decimal({ precision: 40, scale: 20 }).notNull(), + memo: varchar({ length: 255 }).notNull(), + code: varchar({ length: 24 }).notNull(), + createdAt: datetime({ mode: 'string' }).notNull(), + deletedAt: datetime({ mode: 'string' }).default(sql`NULL`), + validUntil: datetime({ mode: 'string' }).notNull(), }) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 5bae06fee..875c59eba 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -1,8 +1,8 @@ -import { bootstrap } from './bootstrap' -import { onShutdown } from '../../../../shared/src/helper/onShutdown' -import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' -import { exportAllCommunities } from './binaryExport' import { Filter } from 'gradido-blockchain-js' +import { onShutdown } from '../../../../shared/src/helper/onShutdown' +import { exportAllCommunities } from './binaryExport' +import { bootstrap } from './bootstrap' +import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' const BATCH_SIZE = 100 @@ -11,11 +11,11 @@ async function main() { const context = await bootstrap() onShutdown(async (reason, error) => { context.logger.info(`shutdown reason: ${reason}`) - if(error) { + if (error) { context.logger.error(error) } }) - + // synchronize to in memory blockchain await syncDbWithBlockchainContext(context, BATCH_SIZE) @@ -33,4 +33,4 @@ main().catch((e) => { // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) process.exit(1) -}) \ No newline at end of file +}) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts index 44fd0b471..90523fa1b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -1,7 +1,7 @@ -import { Context } from '../../Context' +import { Profiler } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../../../config/const' -import { Profiler } from 'gradido-blockchain-js' +import { Context } from '../../Context' export abstract class AbstractSyncRole { private items: T[] = [] @@ -9,17 +9,18 @@ export abstract class AbstractSyncRole { protected logger: Logger constructor(protected readonly context: Context) { - this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`) + this.logger = getLogger( + `${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`, + ) } abstract getDate(): Date abstract loadFromDb(offset: number, count: number): Promise abstract pushToBlockchain(item: T): Promise abstract itemTypeName(): string - + // return count of new loaded items - async ensureFilled(batchSize: number): Promise - { + async ensureFilled(batchSize: number): Promise { if (this.items.length === 0) { let timeUsed: Profiler | undefined if (this.logger.isDebugEnabled()) { @@ -28,7 +29,9 @@ export abstract class AbstractSyncRole { this.items = await this.loadFromDb(this.offset, batchSize) this.offset += this.items.length if (timeUsed && this.items.length) { - this.logger.debug(`${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`) + this.logger.debug( + `${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`, + ) } return this.items.length } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts index 2ff3961b1..fd1ae225f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -1,6 +1,6 @@ import { loadDeletedTransactionLinks } from '../../database' -import { TransactionsSyncRole } from './TransactionsSync.role' import { TransactionDb } from '../../valibot.schema' +import { TransactionsSyncRole } from './TransactionsSync.role' export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { itemTypeName(): string { @@ -10,4 +10,4 @@ export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { async loadFromDb(offset: number, count: number): Promise { return await loadDeletedTransactionLinks(this.context.db, offset, count) } -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts index 30706dba3..847be89ba 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -1,7 +1,7 @@ -import { TransactionLinkDb } from '../../valibot.schema' -import { loadTransactionLinks } from '../../database' -import { transactionLinkDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' +import { transactionLinkDbToTransaction } from '../../convert' +import { loadTransactionLinks } from '../../database' +import { TransactionLinkDb } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' export class TransactionLinksSyncRole extends AbstractSyncRole { @@ -23,4 +23,3 @@ export class TransactionLinksSyncRole extends AbstractSyncRole { @@ -19,10 +19,19 @@ export class TransactionsSyncRole extends AbstractSyncRole { async pushToBlockchain(item: TransactionDb): Promise { const senderCommunityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) - const recipientCommunityContext = this.context.getCommunityContextByUuid(item.linkedUser.communityUuid) + const recipientCommunityContext = this.context.getCommunityContextByUuid( + item.linkedUser.communityUuid, + ) this.context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) - const transaction = transactionDbToTransaction(item, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + const transaction = transactionDbToTransaction( + item, + senderCommunityContext.topicId, + recipientCommunityContext.topicId, + ) + await addTransaction( + senderCommunityContext.blockchain, + recipientCommunityContext.blockchain, + transaction, + ) } } - \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts index acdf5011d..d6b40938f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -1,10 +1,9 @@ -import { CreatedUserDb } from '../../valibot.schema' -import { AbstractSyncRole } from './AbstractSync.role' +import { addRegisterAddressTransaction } from '../../blockchain' +import { userDbToTransaction } from '../../convert' import { loadUsers } from '../../database' import { generateKeyPairUserAccount } from '../../keyPair' -import { userDbToTransaction } from '../../convert' -import { addRegisterAddressTransaction } from '../../blockchain' - +import { CreatedUserDb } from '../../valibot.schema' +import { AbstractSyncRole } from './AbstractSync.role' export class UsersSyncRole extends AbstractSyncRole { getDate(): Date { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts index edef30caa..e67cd70da 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts @@ -1,8 +1,8 @@ -import { Context } from '../../Context' import { Profiler } from 'gradido-blockchain-js' -import { TransactionsSyncRole } from './TransactionsSync.role' +import { Context } from '../../Context' import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' import { TransactionLinksSyncRole } from './TransactionLinksSync.role' +import { TransactionsSyncRole } from './TransactionsSync.role' import { UsersSyncRole } from './UsersSync.role' export async function syncDbWithBlockchainContext(context: Context, batchSize: number) { @@ -11,20 +11,20 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n new UsersSyncRole(context), new TransactionsSyncRole(context), new DeletedTransactionLinksSyncRole(context), - new TransactionLinksSyncRole(context) - ] + new TransactionLinksSyncRole(context), + ] - while (true) { - timeUsed.reset() - const results = await Promise.all(containers.map(c => c.ensureFilled(batchSize))) + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map((c) => c.ensureFilled(batchSize))) const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) // log only, if at least one new item was loaded if (loadedItemsCount && context.logger.isInfoEnabled()) { context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) } - + // remove empty containers - const available = containers.filter(c => !c.isEmpty()) + const available = containers.filter((c) => !c.isEmpty()) if (available.length === 0) { break } @@ -36,4 +36,3 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n await available[0].toBlockchain() } } - diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index dda017cbd..b3432da80 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -1,17 +1,21 @@ -import { CommunityDb, UserDb } from './valibot.schema' -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { CONFIG } from '../../config' -import { HieroId } from '../../schemas/typeGuard.schema' -import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { HieroId } from '../../schemas/typeGuard.schema' +import { CommunityDb, UserDb } from './valibot.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.keyPair`) -export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairCacheManager, topicId: HieroId): void { +export function generateKeyPairCommunity( + community: CommunityDb, + cache: KeyPairCacheManager, + topicId: HieroId, +): void { let seed: MemoryBlock | null = null if (community.foreign) { const randomBuffer = Buffer.alloc(32) @@ -32,33 +36,37 @@ export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairC } export async function generateKeyPairUserAccount( - user: UserDb, - cache: KeyPairCacheManager, - communityTopicId: HieroId -): Promise<{userKeyPair: MemoryBlockPtr, accountKeyPair: MemoryBlockPtr}> { + user: UserDb, + cache: KeyPairCacheManager, + communityTopicId: HieroId, +): Promise<{ userKeyPair: MemoryBlockPtr; accountKeyPair: MemoryBlockPtr }> { const communityKeyPair = cache.findKeyPair(communityTopicId)! const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair) - const userKeyPairKey = new KeyPairIdentifierLogic({ - communityTopicId: communityTopicId, + const userKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, account: { userUuid: user.gradidoId, - accountNr: 0 - } - }).getKey() - const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => Promise.resolve(userKeyPairRole.generateKeyPair())) - - const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) - const accountKeyPairKey = new KeyPairIdentifierLogic({ - communityTopicId: communityTopicId, - account: { - userUuid: user.gradidoId, - accountNr: 1 - } + accountNr: 0, + }, }).getKey() - const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) + const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => + Promise.resolve(userKeyPairRole.generateKeyPair()), + ) + + const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) + const accountKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 1, + }, + }).getKey() + const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => + Promise.resolve(accountKeyPairRole.generateKeyPair()), + ) //logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) return { userKeyPair: userKeyPair.getPublicKey()!, - accountKeyPair: accountKeyPair.getPublicKey()! + accountKeyPair: accountKeyPair.getPublicKey()!, } -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts index 57ae73137..c9b4eccb9 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts @@ -12,4 +12,4 @@ export function calculateOneHashStep(hash: Buffer, data: Buffer): Buffer= 1'), v.maxLength(255, 'expect string length <= 255'), - v.regex(/^[a-zA-Z0-9-_]+$/, - 'expect string to be a valid (alphanumeric, _, -) folder name'), + v.regex(/^[a-zA-Z0-9-_]+$/, 'expect string to be a valid (alphanumeric, _, -) folder name'), ), }) @@ -63,4 +67,4 @@ export type UserDb = v.InferOutput export type CreatedUserDb = v.InferOutput export type TransactionLinkDb = v.InferOutput export type CommunityDb = v.InferOutput -export type CommunityContext = v.InferOutput \ No newline at end of file +export type CommunityContext = v.InferOutput diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index d5ca78ea3..8774bd6c2 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -29,10 +29,14 @@ export const dateSchema = v.pipe( ) export const booleanSchema = v.pipe( - v.union([v.boolean('expect boolean type'), v.number('expect boolean number type'), v.string('expect boolean string type')]), + v.union([ + v.boolean('expect boolean type'), + v.number('expect boolean number type'), + v.string('expect boolean string type'), + ]), v.transform((input) => { if (typeof input === 'number') { - return input != 0 + return input !== 0 } else if (typeof input === 'string') { return input === 'true' } diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts index 4f69ebd98..6ec73a661 100644 --- a/dlt-connector/src/utils/time.ts +++ b/dlt-connector/src/utils/time.ts @@ -43,4 +43,4 @@ export const printTimeDuration = (duration: number): string => { return result } -export const delay = promisify(setTimeout) \ No newline at end of file +export const delay = promisify(setTimeout) From d244cc6b1dc51e0118f7c637a5382cabcde12b72 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:11:23 +0100 Subject: [PATCH 105/226] bug fix --- .../sendToHiero/RegisterAddressTransaction.role.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index 7bb6e1140..ab07a2f83 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -32,7 +32,7 @@ describe('RegisterAddressTransaction.role', () => { const gradidoTransaction = builder.build() expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() const json = JSON.parse(gradidoTransaction.toJson(true)) - expect(json.bodyBytes.json.registerAddress.nameHash).toBe( + expect(json.bodyBytes.registerAddress.nameHash).toBe( 'bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08', ) }) From 842e8be5106757be97242387e52e6afc5d3f3041 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:35:53 +0100 Subject: [PATCH 106/226] update inspector> --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index c7fc92da3..c04199a4c 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit c7fc92da31e80a27558d3887543446079dc55b5e +Subproject commit c04199a4cb88d72a515de2cdc571b634dc2dce99 From 9f9b4aad35e4341b83aa0e0452c89f723f16853e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:03:43 +0100 Subject: [PATCH 107/226] fix Dockerfile --- dlt-connector/Dockerfile | 3 ++- dlt-connector/bun.lock | 6 ++++++ dlt-connector/package.json | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlt-connector/Dockerfile b/dlt-connector/Dockerfile index 234c1df91..ecbcce596 100644 --- a/dlt-connector/Dockerfile +++ b/dlt-connector/Dockerfile @@ -74,6 +74,7 @@ CMD /bin/sh -c "cd dlt-connector && bun install --no-cache --frozen-lockfile && ################################################################################## FROM base as base-src COPY --chown=app:app ./dlt-connector ./dlt-connector +COPY --chown=app:app ./shared/src ./shared/src ################################################################################## # Build ########################################################################## @@ -81,7 +82,7 @@ COPY --chown=app:app ./dlt-connector ./dlt-connector FROM base-src as build RUN cd dlt-connector && bun install --no-cache --frozen-lockfile -RUN cd dlt-connector && bun typecheck && bun run build +RUN cd dlt-connector && bun run build ################################################################################## # TEST ########################################################################### diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index fb882d0b9..1d12dcaf3 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -13,6 +13,8 @@ "@sinclair/typemap": "^0.10.1", "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", + "@types/log4js": "^2.3.5", + "@types/sodium-native": "^2.3.9", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", @@ -277,10 +279,14 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], + "@types/log4js": ["@types/log4js@2.3.5", "", { "dependencies": { "log4js": "*" } }, "sha512-SwF8LkSHqHy9A8GQ67NAYJiGl8zzP4Qtx65Wa+IOxDGdMHxKeoQZjg7m2M1erIT6VK0DYHpu2aTbdLkdkuMHjw=="], + "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="], "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@types/sodium-native": ["@types/sodium-native@2.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-jZIg5ltGH1okmnH3FrLQsgwjcjOVozMSHwSiEm1/LpMekhOMHbQqp21P4H24mizh1BjwI6Q8qmphmD/HJuAqWg=="], + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/uuid": ["@types/uuid@8.3.4", "", {}, "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 57302b3ab..4c90e7b5b 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -27,6 +27,8 @@ "@sinclair/typemap": "^0.10.1", "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", + "@types/log4js": "^2.3.5", + "@types/sodium-native": "^2.3.9", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", From 92ad6b68bf31ee1ef2aabbb87d1a9ceb1e28ffce Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:20:55 +0100 Subject: [PATCH 108/226] adapt backend tests to change seeding data --- .../resolver/TransactionLinkResolver.test.ts | 30 +++++++++---------- .../src/graphql/resolver/UserResolver.test.ts | 24 +++++++-------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index b6abcb0b2..95aa03993 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -947,7 +947,7 @@ describe('TransactionLinkResolver', () => { }) describe('without any filters', () => { - it('finds 6 open transaction links and no deleted or redeemed', async () => { + it('finds 7 open transaction links and no deleted or redeemed', async () => { await expect( query({ query: listTransactionLinksAdmin, @@ -957,14 +957,14 @@ describe('TransactionLinkResolver', () => { expect.objectContaining({ data: { listTransactionLinksAdmin: { - count: 6, + count: 7, links: expect.not.arrayContaining([ expect.objectContaining({ - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', + memo: 'Leider wollte niemand meine Gradidos haben :(', createdAt: expect.any(String), }), expect.objectContaining({ - memo: 'Da habe ich mich wohl etwas übernommen.', + memo: "Kein Trick, keine Zauberrei,\n bei Gradidio sei dabei!", deletedAt: expect.any(String), }), ]), @@ -976,7 +976,7 @@ describe('TransactionLinkResolver', () => { }) describe('all filters are null', () => { - it('finds 6 open transaction links and no deleted or redeemed', async () => { + it('finds 7 open transaction links and no deleted or redeemed', async () => { await expect( query({ query: listTransactionLinksAdmin, @@ -993,10 +993,10 @@ describe('TransactionLinkResolver', () => { expect.objectContaining({ data: { listTransactionLinksAdmin: { - count: 6, + count: 7, links: expect.not.arrayContaining([ expect.objectContaining({ - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', + memo: 'Leider wollte niemand meine Gradidos haben :(', createdAt: expect.any(String), }), expect.objectContaining({ @@ -1012,7 +1012,7 @@ describe('TransactionLinkResolver', () => { }) describe('filter with deleted', () => { - it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => { + it('finds 7 open transaction links, 1 deleted, and no redeemed', async () => { await expect( query({ query: listTransactionLinksAdmin, @@ -1027,10 +1027,10 @@ describe('TransactionLinkResolver', () => { expect.objectContaining({ data: { listTransactionLinksAdmin: { - count: 7, + count: 8, links: expect.arrayContaining([ expect.not.objectContaining({ - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', + memo: 'Leider wollte niemand meine Gradidos haben :(', createdAt: expect.any(String), }), expect.objectContaining({ @@ -1046,7 +1046,7 @@ describe('TransactionLinkResolver', () => { }) describe('filter by expired', () => { - it('finds 5 open transaction links, 1 expired, and no redeemed', async () => { + it('finds 6 open transaction links, 1 expired, and no redeemed', async () => { await expect( query({ query: listTransactionLinksAdmin, @@ -1064,7 +1064,7 @@ describe('TransactionLinkResolver', () => { count: 7, links: expect.arrayContaining([ expect.objectContaining({ - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', + memo: 'Leider wollte niemand meine Gradidos haben :(', createdAt: expect.any(String), }), expect.not.objectContaining({ @@ -1082,7 +1082,7 @@ describe('TransactionLinkResolver', () => { // TODO: works not as expected, because 'redeemedAt' and 'redeemedBy' have to be added to the transaktion link factory describe.skip('filter by redeemed', () => { - it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => { + it('finds 7 open transaction links, 1 deleted, and no redeemed', async () => { await expect( query({ query: listTransactionLinksAdmin, @@ -1099,10 +1099,10 @@ describe('TransactionLinkResolver', () => { expect.objectContaining({ data: { listTransactionLinksAdmin: { - count: 6, + count: 7, links: expect.arrayContaining([ expect.not.objectContaining({ - memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(', + memo: 'Leider wollte niemand meine Gradidos haben :(', createdAt: expect.any(String), }), expect.objectContaining({ diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index cee570c94..8b4faa443 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1040,7 +1040,7 @@ describe('UserResolver', () => { describe('user exists in DB', () => { beforeAll(async () => { - await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, bobBaumeister) }) afterAll(async () => { @@ -1050,7 +1050,7 @@ describe('UserResolver', () => { describe('duration not expired', () => { it('throws an error', async () => { - await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual( expect.objectContaining({ errors: [ new GraphQLError( @@ -1067,7 +1067,7 @@ describe('UserResolver', () => { describe('duration reset to 0', () => { it('returns true', async () => { CONFIG.EMAIL_CODE_REQUEST_TIME = 0 - await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual( expect.objectContaining({ data: { forgotPassword: true, @@ -1078,9 +1078,9 @@ describe('UserResolver', () => { it('sends reset password email', () => { expect(sendResetPasswordEmail).toBeCalledWith({ - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', + firstName: 'Bob', + lastName: 'der Baumeister', + email: 'bob@baumeister.de', language: 'de', resetLink: expect.any(String), timeDurationObject: expect.objectContaining({ @@ -1092,7 +1092,7 @@ describe('UserResolver', () => { it('stores the EMAIL_FORGOT_PASSWORD event in the database', async () => { const userConatct = await UserContact.findOneOrFail({ - where: { email: 'bibi@bloxberg.de' }, + where: { email: 'bob@baumeister.de' }, relations: ['user'], }) await expect(DbEvent.find()).resolves.toContainEqual( @@ -1108,7 +1108,7 @@ describe('UserResolver', () => { describe('request reset password again', () => { it('throws an error', async () => { CONFIG.EMAIL_CODE_REQUEST_TIME = emailCodeRequestTime - await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + await expect(mutate({ mutation: forgotPassword, variables: { email: 'bob@baumeister.de' } })).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('Email already sent less than 10 minutes ago')], }), @@ -1128,8 +1128,8 @@ describe('UserResolver', () => { let emailContact: UserContact beforeAll(async () => { - await userFactory(testEnv, bibiBloxberg) - emailContact = await UserContact.findOneOrFail({ where: { email: bibiBloxberg.email } }) + await userFactory(testEnv, bobBaumeister) + emailContact = await UserContact.findOneOrFail({ where: { email: bobBaumeister.email } }) }) afterAll(async () => { @@ -1140,7 +1140,7 @@ describe('UserResolver', () => { it('throws an error', async () => { jest.clearAllMocks() await expect( - query({ query: queryOptIn, variables: { optIn: 'not-valid' } }), + query({ query: queryOptIn, variables: { email: 'bob@baumeister.de', optIn: 'not-valid' } }), ).resolves.toEqual( expect.objectContaining({ errors: [ @@ -1161,7 +1161,7 @@ describe('UserResolver', () => { await expect( query({ query: queryOptIn, - variables: { optIn: emailContact.emailVerificationCode.toString() }, + variables: { email: 'bob@baumeister.de', optIn: emailContact.emailVerificationCode.toString() }, }), ).resolves.toEqual( expect.objectContaining({ From 5db014d9a3e7ec81bcba33c898099afb70f5296d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:25:30 +0100 Subject: [PATCH 109/226] fix github worker test --- .github/workflows/test_dlt_connector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index 3ba43063f..791d92586 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -58,7 +58,7 @@ jobs: bun-version-file: '.bun-version' - name: install dependencies - run: cd dlt-connector && bun install --frozen-lockfile + run: bun install --filter shared --frozen-lockfile && cd dlt-connector && bun install --frozen-lockfile - name: typecheck && unit test run: | From 703f77b848072b03d9b10b7e5452e9046cf15e45 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:39:15 +0100 Subject: [PATCH 110/226] use default version for gradido node version --- deployment/bare_metal/.env.dist | 1 - dlt-connector/.env.template | 1 - 2 files changed, 2 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index a0e449ac2..e5c86f789 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -94,7 +94,6 @@ DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 DLT_NODE_SERVER_PORT=8340 DLT_NODE_SERVER_URL=$URL_PROTOCOL://$COMMUNITY_HOST/dlt -DLT_GRADIDO_NODE_SERVER_VERSION=0.9.0 DLT_GRADIDO_NODE_SERVER_HOME_FOLDER=/home/gradido/.gradido # used for combining a newsletter on klicktipp with this gradido community diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 18dad36ee..fa5ea0007 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -9,7 +9,6 @@ DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT # Gradido Node Server URL DLT_NODE_SERVER_PORT=$DLT_NODE_SERVER_PORT -DLT_GRADIDO_NODE_SERVER_VERSION=$DLT_GRADIDO_NODE_SERVER_VERSION HIERO_ACTIVE=$HIERO_ACTIVE HIERO_HEDERA_NETWORK=$HIERO_HEDERA_NETWORK From 0d8c5d2d199e7273d3a8b1778b4b4d1199c24884 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 14:23:47 +0100 Subject: [PATCH 111/226] update inspector --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index c04199a4c..69ca3baf0 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit c04199a4cb88d72a515de2cdc571b634dc2dce99 +Subproject commit 69ca3baf09d55f768b3949ef9b7e9a53c25e17a9 From 087a1f10700ede404db0dc1c77a995f507b785c2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 16:43:52 +0100 Subject: [PATCH 112/226] allow communties without users for migrate --- .../migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 7 +++++-- .../db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index c613eb655..05a80806c 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -42,8 +42,11 @@ async function bootstrapCommunities(context: Context): Promise Date: Fri, 14 Nov 2025 16:45:20 +0100 Subject: [PATCH 113/226] fix lint --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index 05a80806c..45eff5ffd 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -46,7 +46,7 @@ async function bootstrapCommunities(context: Context): Promise Date: Fri, 14 Nov 2025 17:02:45 +0100 Subject: [PATCH 114/226] ignore not existing folder on removing --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts index 474df61b8..43459372b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -87,7 +87,7 @@ function prepareFolder(communityContext: CommunityContext): string { ) const binFilePath = path.join(binFileFolder, 'blk00000001.dat') // make sure we work with a clean folder, rm beforehand with all content - fs.rmSync(binFileFolder, { recursive: true }) + fs.rmSync(binFileFolder, { force: true, recursive: true }) fs.mkdirSync(binFileFolder, { recursive: true }) return binFilePath } From 12e61891ba22805fe8e7b41c90b9b93c5fdc203f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 17 Nov 2025 15:14:01 +0100 Subject: [PATCH 115/226] update inspector version --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index 69ca3baf0..36045150d 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 69ca3baf09d55f768b3949ef9b7e9a53c25e17a9 +Subproject commit 36045150da1d6c9d9a568d801f327cee40176646 From d177081df5cec56de32a60fd6bb4c4be5d6724ce Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Tue, 18 Nov 2025 02:25:11 +0100 Subject: [PATCH 116/226] change usage of semaphore to redis-semaphore --- .../graphql/resolver/ContributionResolver.ts | 13 +++++-- .../resolver/TransactionLinkResolver.ts | 19 +++++++--- .../graphql/resolver/TransactionResolver.ts | 13 +++++-- bun.lock | 36 ++++++++++++++----- .../logic/settlePendingSenderTransaction.ts | 11 ++++-- package.json | 2 ++ 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index ac06f012e..5af152090 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -43,7 +43,7 @@ import { import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUnconfirmedContribution/UpdateUnconfirmedContribution.context' import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' -import { TRANSACTIONS_LOCK } from 'database' +// import { TRANSACTIONS_LOCK } from 'database' import { fullName } from 'core' import { calculateDecay, Decay } from 'shared' @@ -61,8 +61,11 @@ import { extractGraphQLFields } from './util/extractGraphQLFields' import { findContributions } from './util/findContributions' import { getLastTransaction } from 'database' import { contributionTransaction } from '@/apis/dltConnector' +import { Redis } from 'ioredis' +import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() +const redisClient = new Redis() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.ContributionResolver`) @Resolver(() => Contribution) @@ -437,7 +440,10 @@ export class ContributionResolver { const logger = createLogger() logger.addContext('contribution', id) // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() + // const releaseLock = await TRANSACTIONS_LOCK.acquire() + const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + await mutex.acquire() + try { const clientTimezoneOffset = getClientTimezoneOffset(context) const contribution = await DbContribution.findOne({ where: { id }, relations: {user: {emailContact: true}} }) @@ -550,7 +556,8 @@ export class ContributionResolver { } await EVENT_ADMIN_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount) } finally { - releaseLock() + // releaseLock() + await mutex.release() } return true } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 869104bae..7d56a7925 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -39,7 +39,7 @@ import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' import { calculateBalance } from '@/util/validate' import { fullName } from 'core' -import { TRANSACTION_LINK_LOCK, TRANSACTIONS_LOCK } from 'database' +// import { TRANSACTION_LINK_LOCK, TRANSACTIONS_LOCK } from 'database' import { calculateDecay, compoundInterest, @@ -68,6 +68,8 @@ import { transactionLinkList } from './util/transactionLinkList' import { SignedTransferPayloadType } from 'shared' import { contributionTransaction, deferredTransferTransaction, redeemDeferredTransferTransaction } from '@/apis/dltConnector' import { CODE_VALID_DAYS_DURATION } from './const/const' +import { Redis } from 'ioredis' +import { Mutex } from 'redis-semaphore' const createLogger = (method: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionLinkResolver.${method}`) @@ -83,6 +85,7 @@ export const transactionLinkCode = (date: Date): string => { const db = AppDatabase.getInstance() +const redisClient = new Redis() export const transactionLinkExpireDate = (date: Date): Date => { const validUntil = new Date(date) @@ -237,7 +240,9 @@ export class TransactionLinkResolver { const user = getUser(context) if (code.match(/^CL-/)) { // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() + // const releaseLock = await TRANSACTIONS_LOCK.acquire() + const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + await mutex.acquire() try { methodLogger.info('redeem contribution link...') const now = new Date() @@ -392,11 +397,14 @@ export class TransactionLinkResolver { await queryRunner.release() } } finally { - releaseLock() + // releaseLock() + await mutex.release() } return true } else { - const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() + // const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() + const mutex = new Mutex(redisClient, 'TRANSACTION_LINK_LOCK') + await mutex.acquire() const now = new Date() try { const transactionLink = await DbTransactionLink.findOne({ where: { code } }) @@ -441,7 +449,8 @@ export class TransactionLinkResolver { transactionLink.amount, ) } finally { - releaseLinkLock() + // releaseLinkLock() + await mutex.release() } return true } diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 359e69b45..679d0f644 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -35,7 +35,7 @@ import { communityUser } from '@/util/communityUser' import { calculateBalance } from '@/util/validate' import { virtualDecayTransaction, virtualLinkTransaction } from '@/util/virtualTransactions' import { fullName } from 'core' -import { TRANSACTIONS_LOCK } from 'database' +// import { TRANSACTIONS_LOCK } from 'database' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLastTransaction } from 'database' @@ -46,8 +46,11 @@ import { getCommunityName, isHomeCommunity } from './util/communities' import { getTransactionList } from './util/getTransactionList' import { transactionLinkSummary } from './util/transactionLinkSummary' import { transferTransaction, redeemDeferredTransferTransaction } from '@/apis/dltConnector' +import { Redis } from 'ioredis' +import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() +const redisClient = new Redis() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionResolver`) export const executeTransaction = async ( @@ -59,7 +62,10 @@ export const executeTransaction = async ( transactionLink?: dbTransactionLink | null, ): Promise => { // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() + // const releaseLock = await TRANSACTIONS_LOCK.acquire() + const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + await mutex.acquire() + const receivedCallDate = new Date() let dltTransactionPromise: Promise = Promise.resolve(null) if (!transactionLink) { @@ -212,7 +218,8 @@ export const executeTransaction = async ( } logger.info(`finished executeTransaction successfully`) } finally { - releaseLock() + // releaseLock() + await mutex.release() } return true } diff --git a/bun.lock b/bun.lock index db5bdb51d..b4e5a9a8d 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,9 @@ "dependencies": { "auto-changelog": "^2.4.0", "cross-env": "^7.0.3", + "ioredis": "^5.8.2", "jose": "^4.14.4", + "redis-semaphore": "^5.6.2", "turbo": "^2.5.0", "uuid": "^8.3.2", }, @@ -778,6 +780,8 @@ "@intlify/vue-i18n-extensions": ["@intlify/vue-i18n-extensions@8.0.0", "", { "dependencies": { "@babel/parser": "^7.24.6", "@intlify/shared": "^10.0.0", "@vue/compiler-dom": "^3.2.45", "vue-i18n": "^10.0.0" }, "peerDependencies": { "vue": "^3.0.0" }, "optionalPeers": ["vue"] }, "sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ=="], + "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], @@ -1758,6 +1762,8 @@ "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], "collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="], @@ -1800,7 +1806,7 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -2370,6 +2376,8 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "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" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], @@ -2658,8 +2666,12 @@ "lodash.clonedeep": ["lodash.clonedeep@4.5.0", "", {}, "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="], + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + "lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="], + "lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="], + "lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="], "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], @@ -2846,7 +2858,7 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -3062,6 +3074,12 @@ "record-cache": ["record-cache@1.2.0", "", { "dependencies": { "b4a": "^1.3.1" } }, "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw=="], + "redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="], + + "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], + + "redis-semaphore": ["redis-semaphore@5.6.2", "", { "dependencies": { "debug": "^4.4.0" }, "peerDependencies": { "ioredis": "^4.1.0 || ^5" }, "optionalPeers": ["ioredis"] }, "sha512-Oh1zOqNa51VC14mwYcmdOyjHpb+y8N1ieqpGxITjkrqPiO8IoCYiXGrSyKEmXH5+UEsl/7OAnju2e0x1TY5Jhg=="], + "reflect-metadata": ["reflect-metadata@0.1.14", "", {}, "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -3232,6 +3250,8 @@ "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], @@ -3674,8 +3694,6 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -3760,6 +3778,8 @@ "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "@jest/transform/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], @@ -3768,14 +3788,14 @@ "@keyv/bigmap/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "@morev/utils/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@nuxt/kit/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "@nuxt/kit/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -3930,8 +3950,6 @@ "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "c12/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], @@ -4296,6 +4314,8 @@ "unplugin-vue-components/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], diff --git a/core/src/graphql/logic/settlePendingSenderTransaction.ts b/core/src/graphql/logic/settlePendingSenderTransaction.ts index 7f55f8ae2..c8ef678ac 100644 --- a/core/src/graphql/logic/settlePendingSenderTransaction.ts +++ b/core/src/graphql/logic/settlePendingSenderTransaction.ts @@ -16,8 +16,11 @@ import { PendingTransactionState } from 'shared' import { calculateSenderBalance } from '../../util/calculateSenderBalance' import { TRANSACTIONS_LOCK, getLastTransaction } from 'database' import { getLogger } from 'log4js' +import { Redis } from 'ioredis' +import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() +const redisClient = new Redis() const logger = getLogger( `${LOG4JS_BASE_CATEGORY_NAME}.graphql.logic.settlePendingSenderTransaction`, ) @@ -29,7 +32,10 @@ export async function settlePendingSenderTransaction( ): Promise { // TODO: synchronisation with TRANSACTION_LOCK of federation-modul necessary!!! // acquire lock - const releaseLock = await TRANSACTIONS_LOCK.acquire() + // const releaseLock = await TRANSACTIONS_LOCK.acquire() + const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + await mutex.acquire() + const queryRunner = db.getDataSource().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') @@ -121,7 +127,8 @@ export async function settlePendingSenderTransaction( throw new Error('X-Com: send Transaction was not successful') } finally { await queryRunner.release() - releaseLock() + // releaseLock() + await mutex.release() } /* void sendTransactionReceivedEmail({ diff --git a/package.json b/package.json index e022f9008..df84c031d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "dependencies": { "auto-changelog": "^2.4.0", "cross-env": "^7.0.3", + "ioredis": "^5.8.2", "jose": "^4.14.4", + "redis-semaphore": "^5.6.2", "turbo": "^2.5.0", "uuid": "^8.3.2" }, From 5f7383a486301b2e58373407d5b5eb11b3ae651d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 13:54:48 +0100 Subject: [PATCH 117/226] better error expression, update gradido node default version, update inspector, allow phpmyadmin importing big sql files --- dlt-connector/src/config/schema.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 34 +++++++++---------- docker-compose.override.yml | 1 + inspector | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 45ef83831..3abb84f6a 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -84,7 +84,7 @@ export const configSchema = v.object({ v.string('The version of the DLT node server, for example: 0.9.0'), v.regex(/^\d+\.\d+\.\d+$/), ), - '0.9.1', + '0.9.2', ), DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( v.string('The home folder for the gradido dlt node server'), diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index 8f198b5c8..581405207 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -104,23 +104,23 @@ export async function loadTransactions( return result.map((row: any) => { // console.log(row) - // check for consistent data beforehand - const userCreatedAt = new Date(row.user.createdAt) - const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) - const balanceDate = new Date(row.transaction.balanceDate) - if ( - userCreatedAt.getTime() > balanceDate.getTime() || - linkedUserCreatedAd.getTime() > balanceDate.getTime() - ) { - logger.error(`table row: `, row) - throw new Error('at least one user was created after transaction balance date, logic error!') - } - - let amount = GradidoUnit.fromString(row.transaction.amount) - if (row.transaction.typeId === TransactionTypeId.SEND) { - amount = amount.mul(new GradidoUnit(-1)) - } try { + // check for consistent data beforehand + const userCreatedAt = new Date(row.user.createdAt) + const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) + const balanceDate = new Date(row.transaction.balanceDate) + if ( + userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ) { + logger.error(`table row: `, row) + throw new Error('at least one user was created after transaction balance date, logic error!') + } + + let amount = GradidoUnit.fromString(row.transaction.amount) + if (row.transaction.typeId === TransactionTypeId.SEND) { + amount = amount.mul(new GradidoUnit(-1)) + } return v.parse(transactionDbSchema, { ...row.transaction, transactionLinkCode: row.transactionLink ? row.transactionLink.code : null, @@ -128,8 +128,8 @@ export async function loadTransactions( linkedUser: row.linkedUser, }) } catch (e) { + logger.error(`table row: ${JSON.stringify(row, null, 2)}`) if (e instanceof v.ValiError) { - logger.error(`table row: ${JSON.stringify(row, null, 2)}`) logger.error(v.flatten(e.issues)) } throw e diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 3898f9991..8c3d06b39 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -199,6 +199,7 @@ services: - debug environment: - PMA_ARBITRARY=1 + - UPLOAD_LIMIT=200M #restart: always ports: - 8074:80 diff --git a/inspector b/inspector index 36045150d..0c14b7eea 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 36045150da1d6c9d9a568d801f327cee40176646 +Subproject commit 0c14b7eea29b8911cbe3cb303f5b0b61ce9bf6f4 From f70c59f9b33e13fef7a0f363a55d5d818090e3c1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 14:05:20 +0100 Subject: [PATCH 118/226] fix lint --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index 581405207..58a5d364e 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -114,7 +114,9 @@ export async function loadTransactions( linkedUserCreatedAd.getTime() > balanceDate.getTime() ) { logger.error(`table row: `, row) - throw new Error('at least one user was created after transaction balance date, logic error!') + throw new Error( + 'at least one user was created after transaction balance date, logic error!', + ) } let amount = GradidoUnit.fromString(row.transaction.amount) From 67b2506241b9164c06888e5ba2ba5cbfdf5051df Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 14:42:58 +0100 Subject: [PATCH 119/226] update login subtitle text --- frontend/src/locales/de.json | 2 +- frontend/src/locales/en.json | 2 +- frontend/src/locales/es.json | 2 +- frontend/src/locales/fr.json | 2 +- frontend/src/locales/nl.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index e7741f83d..4e9cdfdd5 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -266,7 +266,7 @@ "expiredOn": "Abgelaufen am", "has-account": "Du besitzt bereits ein Gradido Konto?", "header": "Gradidos versenden per Link", - "isFree": "Gradido ist weltweit kostenfrei.", + "isFree": "Gemeinschaftsbasiert – Dezentral – Open Source", "link-and-text-copied": "Der Link und deine Nachricht wurden in die Zwischenablage kopiert. Du kannst ihn jetzt in eine E-Mail oder Nachricht einfügen.", "link-copied": "Link wurde in die Zwischenablage kopiert. Du kannst ihn jetzt in eine E-Mail oder Nachricht einfügen.", "link-deleted": "Der Link wurde am {date} gelöscht.", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index d0ab23d1f..9e96a497b 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -266,7 +266,7 @@ "expiredOn": "Expired on", "has-account": "You already have a Gradido account?", "header": "Send Gradidos via link", - "isFree": "Gradido is free of charge worldwide.", + "isFree": "Community-based – Decentralized – Open Source", "link-and-text-copied": "The link and your message have been copied to the clipboard. You can now include it in an email or message.", "link-copied": "Link has been copied to the clipboard. You can now paste it into an email or message.", "link-deleted": "The link was deleted on {date}.", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index 9a0d4283f..905466540 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -214,7 +214,7 @@ "expiredOn": "Vencido el:", "has-account": "Ya tienes una cuenta Gradido?", "header": "Transferir Gradidos por medio de un enlace", - "isFree": "Gradido es gratis en todo el mundo.", + "isFree": "Comunitario – Descentralizado – Código abierto", "link-and-text-copied": "El enlace y su mensaje se han copiado en el portapapeles. Ahora puedes ponerlo en un correo electrónico o mensaje.", "link-copied": "El enlace se ha copiado en el portapapeles. Ahora puedes pegarlo en un correo electrónico o mensaje.", "link-deleted": "El enlace se eliminó el {date}.", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 55bdf4ee3..8024d468e 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -220,7 +220,7 @@ "expiredOn": "A expiré le", "has-account": "Vous avez déjà un compte Gradido?", "header": "Envoyer des Gradidos via lien", - "isFree": "Gradido est gratuit mondialement.", + "isFree": "Communautaire – Décentralisé – Open Source", "link-and-text-copied": "Le lien et votre message ont été copiés dans le presse-papier. Vous pouvez maintenant le joindre à un email ou à un message..", "link-copied": "Le lien a été copié dans le presse-papier. Vous pouvez désormais le coller dans votre email ou votre message.", "link-deleted": "Le lien a été supprimé le on {date}.", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index 9b3f3d265..98eb6d2ad 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -214,7 +214,7 @@ "expiredOn": "Afgelopen op", "has-account": "Heb je al een Gradido rekening?", "header": "Gradidos per link versturen", - "isFree": "Gradido is gratis wereldwijd.", + "isFree": "Gemeenschappelijk – Decentraal – Open Source", "link-and-text-copied": "De link en jouw bericht werden naar het klembord gekopieerd. Je kunt ze nu in een email of bericht invoegen.", "link-copied": "Link werd naar het klembord gekopieerd. Je kunt deze nu in een email of bericht invoegen.", "link-deleted": "De link werd op {date} verwijderd.", From f0506923fc36d0a6338f140dc41ae6ea9cdb52af Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 15:34:14 +0100 Subject: [PATCH 120/226] use Copy-Symbol instead of link for copy function, change order --- frontend/src/components/ClipboardCopy.vue | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue index d6e0d6aff..755126620 100644 --- a/frontend/src/components/ClipboardCopy.vue +++ b/frontend/src/components/ClipboardCopy.vue @@ -2,21 +2,6 @@
- - -
-
+
+
+ + From 1158d13da3d12e0764e401e225892f8ac6223e78 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 15:37:10 +0100 Subject: [PATCH 121/226] change order in transactions list for links --- .../src/components/TransactionLinks/TransactionLink.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/TransactionLinks/TransactionLink.vue b/frontend/src/components/TransactionLinks/TransactionLink.vue index 2f414f894..9ec81675b 100644 --- a/frontend/src/components/TransactionLinks/TransactionLink.vue +++ b/frontend/src/components/TransactionLinks/TransactionLink.vue @@ -18,10 +18,6 @@ - - - {{ $t('gdd_per_link.copy-link') }} - {{ $t('gdd_per_link.copy-link-with-text') }} + + + {{ $t('gdd_per_link.copy-link') }} + Date: Wed, 19 Nov 2025 16:19:21 +0100 Subject: [PATCH 122/226] update new fotos, remove not used big scaled version of image --- frontend/public/img/template/Foto_01.jpg | Bin 689447 -> 0 bytes .../public/img/template/Foto_04_2400_small.jpg | Bin 0 -> 172015 bytes .../public/img/template/Foto_05_2400_small.jpg | Bin 0 -> 578096 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 frontend/public/img/template/Foto_01.jpg create mode 100644 frontend/public/img/template/Foto_04_2400_small.jpg create mode 100644 frontend/public/img/template/Foto_05_2400_small.jpg diff --git a/frontend/public/img/template/Foto_01.jpg b/frontend/public/img/template/Foto_01.jpg deleted file mode 100644 index 6238da44c7f4cf56571bdad65b003242f05cbec7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 689447 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

@>T+}r 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�o@=riYA%!-OONe@wUQYtxMJjxGh^4sNJe2eJOSl?>x=NKOS#vUg2Fu_ftTrytRlYCoao^EvPat^+bqQ%TXe~>BxUMuj z9}MgvO`_8O0GJnp7K*C9KxMk{OI*KXbu|SN+Jo@#3a^>)r3w?+y_G-+4@9&?7*@?0 z0OK&JmRL)k(1FdKRuskNCH`V^7QZFmbZL_((5tCgpg24>J{y#AKbXmZl;!+Nb_*!6 zsd`G#!Vje%1#QrK+4C$Rg&&MdTGs-j0bj69u{{RKY{sXzDI!85~i}_+Jvf;N=1}kGF zV4mX91Z-@|bJb>Wq7%S;08lVT} zcj3>#(xol?JXbyx)|(MgZY-S8D;yK-#CYuAx+TugkT9yICz)9 zUS3>kY_XvL_FnQ2G329r=9~S%5Qx7dd9xO7I{ZcK*1%_IBE_99G#EOmH5wMX2S{=R zm;R;sf>i$iDMEd#_(Eelq_#pwp0Xu2F#vFHM`aVyW#0*h(c6e;%x`*}AgZPVERt8tpwJ6=XKM;dUP&M%%kUT9In%&Mq z0Ub#wELkf8Qd+3;e^R{gQiWHUm|Im&zN6tTLBZOO%%v#CGMaD3L8>ZiBBYCly8i(7 zJH?>X*1E?nQyFQ<{{Utr%>x3Apki@-6WjEsDx1`;1x%wdBUzM}%lg8@@}z6;+;P+@-=~V=UF^kr;q^0p6Z1g}w=b z$*Wa)Ve*cwKm3l$+dNW+p`gGvH}aIQ&G8ihz*Ni@pAxn_RLD^oitNHOLhchz@vuZ~ z1@^|G{tpp80HA>I1;PU;hkpTPmbT8uVf(PL&=d|wAMPII`#MvchgQ1mmchwhXRv_x z21RMvViSJ65u7M4Fw;L#*uJiWdkRKrY)lQyX+_87wAvpt6ufL7Qia5EXamR8Lp7f7 z;ypF2us$v)=7rp0c~JPGA4a2uc#CBmje0p-j!Q|hgEBCM`xHXLGwuql7uqZ>*9Ew_ zsSQf|eMg?~yDARX!mbGNJl$7B4YiZV%@L3pcW9&T15XxQ5ldB~P|2vEzU_OsKU3Xh zJ5eO|`wXTpHK@Gy+Z^C_Otw`GLFP1s{m! zPY^4)0PpM^6D+o&UdPj6Z`?e{y1}qe1w|6SS71_1=&=e8#Hm1m$3rcxQt);LyXs+g z;@(_7EYjjdxZJ#E3m^@>;Ooqqd;yp9OTXHROePh=k?~!TAe+a&! z#iCwbUOkfX@O1osqX#x0iNUuQ+J^ZI@;lasV;ghAP<2;j4%;ggb5*h0#xrLZH_aU< z)Efl{(3Mb+Ujir~IbLEOoKYFX+4|;U`2xGmjI_(B1%XlH0mg-?bU+=NajWSbr3-Hj zX%S1D#mu8Eim26J5j(B)Koz9OTvy?p=ns}zVg%kz<44-LNBO@(3sWak=weZ$IJ0#W zlho2@5iE+J{Gm){Ba)4B;8%t>vM>R5B8fmVU5&|R%tD(P@m%2_G1hqAB}7G}K{C_{ zHntOP0ZDl>S=4)e2m(=RmfW)7Thed^l^I{Gs&l`D1Gg{cB^ov|sZhhHHpWXUW9;h` zAlC#FlXm!sr4Qv1SPB;}v}iXCl7nBws#lQn54Z~lW!d@G%WCDtJx(si#9l}E)&4z2MnsCExS4(vD37Kk*IXOb_*rg9kPac(va2*u$>{Kxs1_J%qH zCEY*}+7ATmy^9Ogf9w*H-v@~8e##RLF%5uq1F)_HJ1F@CHpQ-ysQ%DKb!9z%7-ZS5 z2@^kv*)0peKroh8bhx>I=R_bXTd@VVlDvi#xnn2H;Ns=ve$|s(P+Bs*!w?Z_)a0V` zH#nr5BKm+NX?b$L+_-nE(fjH9yZAs# z9%Y6gUZ7^czRn+-dydobPjEcpI>H@l3#1EdFLQ+M4#Savh?*{Dt|{|Wah@Vf7Ats` zuCmAm_NygErRwBlg|X%>(PHFRVQbvDQV+_vNyJfCnP4p`LGCRSS1ux1TMa8=M6WZ= zM7H265fD3ZOOjftdfH8-7eF6K>81Tk8U^`{%(6#_L@ITHAexJOx+~05Qks=gUWB~b zCmBk*dnSlK2ni_QcB4da5j??aIs*h?7gw+b3rk#t7Kv{v9#)F-4M9v-2oA(TDAiNE zmaytR;4OUv9!KRDBEv($$nG`;TtSurZNnv#PcqjIf94!m2mNv>I+#;*MlJekaf&)4?FY+2{d^A%k0Xrdl%0%`(mYDJh zXibz>^qvs%HlR_srb>ZuKBM^sIZ^d$sJwxb2(@ch{2__&-ypN^A;a-0*X$MW~^@&5pWyr=bl7gL<> z4#S_E>VHyn`&wqm^-Si3`UvcnAawuWMg{ z@7WvdL#RNG-L4|n9oQ5?gskih6X5eLdz#yG%t+T(T z>>?vlRJZObTY}3~7ZN3i1*z=}TEmU@U<4#`h-td7Jr%20YGWXAP@kmdj9~}1d9qsR5z6# zs8AD?mI_!!)58uDEAA=eh<%X#q|=E5Fy-)tFW8h+6i8Cl2MY9Hrl>XhO9)VHrIR4# zL*iTniYf6?OUR`S1Lj){LfI*6K!uA}{@`E~aM*XZ$n$|$)?a~v@RePNk;Z0a%?VTI!+S1g|jvXaLRcJK>J^oL=P&G-Vw(m zK(MX(l}+I%W{dk%+SBJT`v_zx7F1QEq6$c=r2hc+ETt>tq*z-}EAUNdiP<|!((q=_vK!{naSAx4#A+{~u#_v~Fh+`u_vGhs52jQIb6A45D^?_jqY5JM! zstMK*>^~5zVYG_qiVKpqqr^p7v>Q~gyN3}a^dy)c{-impC0vhjIL{M8?Y;iL_x)AW@1jNWz50tJLxq zClwx|xE)Fxa%F)A!^{TvgM{>_VYZM8EHl9{sC`s#c0leUKvq5mR|svkdrj%aBOvK{ zm&X}TTjWi^*P;Z|q*YWkwrGp9VU*sR3xNSmAf(+C@Yn7T?kpdqRRMmKkJlS$AD$)b zih0qeKXA=f*If%3(Q#d1nuPi=KgC7IkOI2O&uf?B1$E7RWoDCYa1g8TiW^VdUVB8B zs1A(Yt-i|4dJ8}pKA|NcwDKxtgJw;Z8wUF)gw?D8|*j0NxJp5?=32W36a zF#tzrTZhsqmVA@so`gwoBBOJGTRJ45Gh5k8 zt-fPg)AtC0f^=GX*pMnIh~l#TArRm4#U->C2t`e(hz)X9Mr&y~?bI+}CDp=SDrGQ* zPb(aj!taD{_jUYI-5|NyahS2oB2i6EJ|}Uah>WvpPOVs%RxP{{YgKxL@p&&1)pj)= z*4lg_?I=m+lilSsUxEfg^`1v~UGgJPp$|D1$=}9w9*L#4sq?Wnct{w9!Wo)~&M+vx zCH^1OO$h6_k>W!D1-Wz3;?N^nmK{FfD;Ov#d_hztekrj6RMr!LEEbF+9H7XCn#SKS z;R$nF>WRqc`mgFxD)0s zZSaM5n1L95j8*ia_W;=P5YMpH$W(h51L7+^u=RRiESf%A^(m>0W27P047Q#(4o?)T z`i2g>mE>X$Le4h4GT2vqF{<#V)U?i_^Ki4*FYohqwDZ=eqUri z2eYy~e>Yj>JSQKXCFFbf`~24rkNJaa!SqJQinye0fbDMOVtO#p_WDI%69hQ9(sdp_ zzXuch6UGY!{w7ntC0UmCRDcEj?jl`V%0{|4SCn3@;$6#hV!q;dF0_B-$M5j#QU+0JR?K3JUqbxNhnir!8bX@r;ZPC&3?ms> z3kldL9penpXl42dTBU@kW$pQmASqcbX^%-v3T?goCIkb5#lDSsL*`$~GQ(>2TL@sj z?rH+krV#$T_RDdR{OC6in%=wsb`~oKa9chdu zMWHavnvD>LqMzm>u6V?d6WFb|sg^FENc(tLuI@w@oF7QM%?HFEny$bhYyrZdv2yMd z>JXZIKmqz7s9TPU^8s4;#b9mLSMB`fIVBzOgdBSCLof~4{^EpyV~@l^bo)Of3^t#c z3dJ|Eghn^X>2u6d(OyZ7&sd}y@f%hM`)p7mpNNVTz6oIkp}3R#gJm2c@TB6D02fl3 zQj9J#ocAKc4o|$b#~(ZaWP{ofyObF^dAgMPD(p%qB?QWz*f6TvABxiSg03}o*lBCT zr?!Y1{`&-1#dlzxPg=s6au-pf{6&H&t4=d7Haro(*Dj;yjkhhsS&W^^zZt(dE6G}% z?mWuxK4Boo1H{^`*#HEqv7AnWwJP^1fKzR;@lZnyJs{Z&;GR%8xf!iQ2a4>kxEA7; z9#1imqK9F;zRw8BY>dsdji9zh2*X?V>W%dOcfXKb(|^%hW_PmLa)R7mXW|*LsTq@0e;=2h=(-hnWpz%mN13!=^Kap${lDWCkm|KMs&oO*qQ>VE8Z* zMh)m-pz{;>LL8KnvRBgx)jf|lsI}R4yY&Tpu{^=*!k*87?GBqZ5Ui1_jhkQw3J=ah z0n@73D5kp+g*Nso6iJlCDj~{K%k4& zU2pXi8Q5C3L55hDnR5pN)G->_vYt3sg++g^*HFOanN9aDN5P z6iPkc{Y_+0Tu8u%2Yp@#$_mxNT)nk8%4$-@*p1Pt+&3H=tZ$xUrxsS3L4KwB`|X}0 z1|GaD^AOz>2R;^``XM6{`Mf<2v|lc(Z%{{X_CUx$y+Dc9qi?>L>{J?|?AvOD__ zfp?)P=>8J#*|s4{t0|U|k3q!=R?JIy^(qKC{&Lu0tZi>(GSTMF=aN@y&HeMzsM#?Nkn@jR9-1Rj*?WG^=|?k!sP z81LfD8SSzfEDaR8V90Ky8?EaDjae4==C=Z0c zzvdqpqZF&+5SaN+MGR}KNT-sQL=XrNFhr5VklzyA^Tq7{GsY=P;WRJ_fVKipqRRA2sQyUFSMh=aptd`I>Ik3SJ>o!x63u9h6XcPQ}{YSG~T z05QtBQiJ=r6EFi`H#<{oz}kPP*N&5?g0iK|Ue{3iiaHUTXzc2p2A}Q_sPy=qPyj9Z zmk=@99}l162B5x4`YK)FIiahal(JKeY^(V4RC#|nE$>>EkI7QCjD4l-dZSTh_!w>u z^cnq28rBbji~jCXo4sGS*NX6@1_~g(C4LW(Tgv@Fr5&>4!YD8EkJ!_-CjS7K{{GWt zqjza9-J;QVI^BX=va(BBxb7j8gDav7=S&KZ&DN~3g z7NQNMJ3prq!*2SU+bwn2g<;r)Ch*kOwa=7(-Mn56qRq)#7gk+*l4doME*k&s#L$jT3AJRkJ%vj{X?>S2tK0& zfazN=PqG^u`2`4YFJWI(0^pa;!A!oO1X5eGQDqdVXh`Ld#kBD-2V1pEGOnVkANG_$ zfJU_VmXgb&P&Yk@98i}ZNJ_28B4tA#bUH+Za^E6*=1ce>mpw|*g15ByS~}W7oFww9 z2A)iKWD3@xrF#bbqim`ENl-Wt@(+eI`+&vgWf6wkK;#M|=fruiMlEBs{lwlH)wi$W z4B_tg?h;ol>lr1KjjG74Gte>tH!W4vbGE1`6Ob&#eE#Dk6IE9;W~9YA9h69G`{~J7 zlPwe*qBvRPT_81~RYv@4CFkk^&lBYx_Kg&&QHs-GdSoXc`(Q-b$v`fe_K1xL#-CGA zU|Rm85P^?LMbI8)dEXYsq45agh`1>b+MQSjvFwJGQlu?z15#7-7zMSlk``Y`84fWa z9;GiaVBCRbkrqY?1?-5XTy;cr4fzqpDC@jt|%L%$J-8}V@}_Jo&J&zhcLWrrrJ#N#S)UvXh&OB>6E zqSquWSP%CTWhTw(IPCp~A9k^o5|qNhN2IN2UTY!cl;FcOJtM!d_yJ(A^#heZ*pzB4 zq(jHB>g9NVXB8gwzo}VoElWzkS~s!`J2F$NBOtwi#vHLv;k_`AXQfZP9?V*Uk*4cs zcrsK6Q8{-5xN+d^{{W~{)y2{&0Ba!uw#&{(Haakg7Q-$eY&AX}Kd2a6QANvE3Yyu}Ax`ZfYTjE>^AiPKR zije>Sa;%KGAtCW9;VR5Yg05{`woS%=! z>T*xI2T!|?4oBggVjDbw@TcAb7Wea{)h!Te`496&8f;mXu!US+>j zw)$od+%Q?`v$X9x{C+dWc77YkcR2e_v&IM|EI>Zo0hq5*Bp6rBxd>7A{I1H^_y`YD zl8f;P*H4J~EQI`;XC&bJghqL|g>dn4R!@pzOb=09lj;c7@gg29{lg&WKcsbd2NE+{ zsfQMA58JT*8cIM9IRJI7kGMQ3yCZrEu~N&?2D_C8+`4jSWqAt5gNKNU+#s?Bss)%4 z)m;lEN&YA!VH^dL=JSwRDI8Bxrp1v0hAJc1OUIFnRE_$Ci^)aERx$y`<9#%|`2PU7 zq~s=z9tX^252*1k%&^*YF$7lg{{S-F`47R!jOkJcBqeZVGc0c#o-BA^h!TcNW%1Q< z)Uj~Uu?9n3bze}>fD2?IBsW?wWMLMbFT}A`Rx4!Rf$Sgxe9QurSP$wV%CAHp6^PUO zgzlT|?3E|U7?F~p@+z?tQXw5G=c&?^&jXP(`S>WhURb+Lt_CLS%kBz#d_++4RDiC*3dR;r zKzYiGMBnQOa)$`GM|e-FH5lS#Sb|XlKaSDSQFPC$eNm84Dbgw>=5Dqn-z6JLTI}G0BLYOTFwMqblLBNi9loIJ%32p4+I*S6^9`Q z?sbjC9hCZ)(P8d-;qfYn&pxJSk-?zY*g~8m-~+@Pco00%+9LXm$r7-NK_6tG0fe33 zv`VPf1bnDCx;EvVm!PiE$m)=FShY3Vvj8Zd_=Ic6UvToOQ<4Nmak{$X_c3btm++uN zVwQjpPrw(Gtjbe63Hp};7#=F>+6WUW%vaq&V-;fS_?3cI!h9u@L*XW5py#;~#89n+ z`vAb~P>*EDeoRzgWkFkNFPb4ZB4XQXe1I^3u($=YIow`^y7=c#m^&Zoe4>k~k2m}`tvrGOa53XF-)lRRSdkO&o@ICS={{U37 z`md>-38!fkq>k|kZP5=@M#Nu%R*_m_eYv{#I+i+8n=5ql;C7^BKPK8 zGAU%qQ(h$r?ZFvSV6vvuA5+tZW>~|_;3g8GSD40=ajK~mg_fwkNrX|9+8-A>ih$pw zsR9sSevnb$IO;6O>;n3l{b3GJsM+TslXHOFKsFe5dr*9#Q)kT%+bcFTJ3eW(bpQ?I zJ5zCj*k@Dbj2@+cy@hn2G#YFgE^!94SS91?TcgqrQpA=@))_dIGdJ#EmY0z_?Q{1B zx|4CD`vT?f;kPAbN>bw!8CQZ=qEd1Kb{oX_psjvYNYEY);BagC;ROYDkn&TN{Uc`#Tw@YLAa^Kh`?VT#9*dU61z92uc@R|ze{sY<&4PaN&pu!SE+Vc8Z30gi z?MZAYQI&k7zz2wX5Sn9HS1k7|fc#?uY+L$>muKNtzx~-l&*CHdnIbmo97MXhj%NXh z4QXNSh+>y^aodaa8Ab)nfoQPOEmny4%}j4khAVzYe{8;z6u0s}+@oH3B}4wE5sJ)j z_cO&;x8_$E&4ZayaHb3P$=|#e*?;~jR=~t|Il*3%QL(`)u%JIMbqnIB5Ls{Hx{dz8!H1Xmmf;_kIP%96o74)G%$z0CHno1@%-wC+ z{N2%WWVorfDo^l)r+vaQ0yK&ugKLvDh#v`MjnNQ9o0bimVjmLhU!(_m@P&Mq6?7v) zU1G{$tm}0Nn~y3qI9XmIq;w?{${%G+o(oRGu>=6S0s4tmNG!4Q^Brvy6AO*%xXJoO z9ue+ZAiM+h4_+b5`l-N1)RQI^Yh!VgY<@sQT69%a3cqt2T6jiCiiev@K-Fus>-;kv z9Zs(w)arD#T!qpAaYgJdsJ2e!M_7u8F;1Ca(eoqi?`u?{+^AY}$88`-|lrTNj3-2FIqw z_aDwO2k^Dnw3mFxxMH@##`ufw0?(L@KMVro=`r;&wiU-s#}sF?V2X)QMNrdG3b3kB zNrxjCwp4c5MJv+bG@z^TvB*}r8x{-X1mx2qyZl1xJ7j9u08~3HdqA*c3UlzIXAcuh zTpS6+>~a7dh>oAM0+{hISB^nNqm>LCqHjN`(@O}&K=|qpiB_P=9J@<)RZhK8Ce`KG zgdH0z>-9Fp4js7n2bh(W| zVVH%rjARJKtY5rDE>J;HMk*AqC%1HCO1qm$XopbII=1R^SegS)<%lGs*inYAnnj9b zQcL#byX1ekvs){im1iHQ43EbUnykxGdMnzGTojTS888us$)fiUoppBZHe&{!~&TZ58Dd+ml`4zdTb(h zQ^t7MtHL2+dlQdA+z>!zDsBni>U<0413WG<&@G2Y6PMWSZ~BC_aYd)v5C@LO7sRxD z%8x6}8}fow&upQl>(n$?sQrY+@bL?;4Df*#%Fs#iIkyA`9U$a7!Kc*wpws}Uw7*ad z5EQUhd`=+@mj-?R0K~D@$9{-Kykpp4ZtfYU;cUtiEc(V&MX!{g-k37#yv>4YC8-LGbq&3srKW0GD7H7x(oq%wNo3jy^Ghmh% z@;3<;L-TNp0@KVy08LaSW5EHHrv_w!@aiBeB9l==M9XAb>QK)ql}3$&e*~>AzqCSo zJiQQaY7bc-GQgUOR7EM`3|0@`B_;_?Al1Mvn{SJnmvWe&kk;YP`WQ8F2Z&FmY)d^m zQp?{o^{H_8k+%dbFclU#tsY=#T{1V+Q|QL{v9rz8wlSHk8-aDCM5|w8JSVi_DGO(U z}P~%XMX_Wm`b*zo(XJZjj>bk0r)JGLK zFH3*mnkO{kvrZjqF)$e5ON9^wTTALzu3!-6DNN0QzLdf$4f0TLMpZ>sUxE?mcgr(j zh0X;vF`WPhAfeHUJkjnkDx)I4>OSoZl?DX(_Jm`4woUgDtwE4>2J-=H`i$gNou*#a z4cFl2%R}=#GPuH#(#Q&WA*BA~>p!5*v3=|TbOo$_ zaQggl_`jt7IL;rb$KrGN?3|N^J)A!;STFaVtxumBXYC*9DxaB2_<(xD{m<;B+x`l; z`JYJdlWbZRS#sU^ipNzx-`qAC-#?36l<}-i$S(SopLV|;?Ch`bsFObUiWZt}gF<*c z<{d+=Mg;mL$_Kbj<6Wup8!rHSm#(BU>EwS@ZdOIUyu)M7XO4%dQRo(a6Oox$84 zp&g)-hm@-L(hN^6u$98w4~QUZs1Gpkg6G^S)`0Ft?j2SzR><$90k4GfGeWwkmw87} z1|#1~>OKTjUTR*5!)IZaWIUB020?K;7FPBLQHlJ@im|785VnmjYV(3D0ZSD0$2_b%CM}8OG!2^*gQ+39KI zpnc0}!BRbTDin|N0e!uwoY|%Fe&Co(-EnYBOYS}+DkAE|iH~#?HbwIXVDJppe z!m1-}(lq%VH6=Q>`-IU^S_u3S%<^FoRdEi=HWRC32H$N*qLniYAo&;PEP{o2hF4_< zn*eh-eZ|*et2}-!qBStDJx70J1+^N{+TJs zYp@o=0jS~aJ-}=O@fF(kPzxi`Xe_yO6~0LHi|_XUXlbz&IdbK#?LkZ)(Qa&^3Mec- zpyxOzRf4T|eMV3j*bfqxeg%V>`zIqHe4Ui!HBD3$yKrJ-D#xN%y6Cp2aJDj_uWaGw zFnKt5hqL!(%1hV3xZVZ?_a!NqKhiHFHlY&=Oq&EYtf}#Z z0O?f_Zx4qh`l=V|Hl%<&GKGL1LX(H;k}*RX=?G(8Q=EK4x+;1WLs)ekVN1WadF&*j8mmT!=5LnTBd;`)UGCgJ3@832L$y_?wilW917X z0o1Q?Q|qT-PEHj1O1GP_FWTb+Itq3%uj&{@8V_=~pwbaLeDx4`3TycDDTBk)?2B5c z4{jo^lgx8L%60js7mDgOw;Cw6XW|D{c{rhcB|^}m3HLcF zRv(OvFh*4mR9RDzo?9@5GX3#^MNDJp`QfZQu%Ftz^r|t(P$D1KH~dBLc;|> zx2f_(ikxO(%7K>9ZLjMq0JicTIBk2Ikou2euA>PR4xcQ)DY9RZKn@;zEGY!Un@grW+B8LPOQxb6ht6 z0Kdh(f>h^j64cu;nWBKbgPGVOz$zvoS`wBf2C~YzWehNs)zq=rhiPgsTWE{O!S(~< zJjDTwhAKYbhDo);L$&AWfLIthBEv^>^A4=gR`OVAxRvHnACT02w{TMa2R%1L348f&uZg8YyMVG-9au|Rw%9-+Yk(|%Ohb+KU-bpB%j2lFfqg8ceM6JysU zO`J{3*`a~^Awbh8hF^%lZ19}^zXt?x%6&$8#jwLD1;?x^X%SuVE+UvbIK7 z+)Ko|x#()PWs7-3_{3D>DDjz4mi$7dZYt=EHX-v6-E0@X4{%veMS1YOy*@_ZuG0E5aLs+iS>E3L8esAfz=(8^KS^ z1-)q!seD;nrFU%k25Oiz?o&*S8H$FX-z{$7WTHG|Mc=={&w*dX$DthuxbHYfP6k3G zpo0pk=!!@)Y7rG;#`1AFmdAkwSHw&2BU>18ey5JF<#0t64LrxBTTl@(@sLHFD9Xoi ztBdyKu!_cqGEfN6zGXOTV7{oAObfLiJVol-{-K%=l&BxSZ`2UN)9#i7M1{>D7I@>t za5!zGzmNAmvSe)s7a zYfs!9o|zF?sj*1{7e=q)vFBwBSuK%pI0>gW5o&^$CBuSSassVJDy)={g%`}Zr(KD9 zR>e|Kp>VzCc1kIN4+wl&#w+i{VN>DrJanO1wMDJ-QE9tU#+Tt3TSmqZpf!L8pYe*GpYSw!v6pS9E8*l zBVh;aE3EM)9YZIgz}HUl180BcA;pzAqLFQSj!~Nq#Yy8S)#fLmiucsh^(Ym2f^suy zIV%uUZOhl+;#+cRVMt)O!L$ph)M46akH~-!(UI?wUlD*U)UX7WArpH1giGar2Dt5k&dPjJ7;*!Om9jxY zWA;GEhXZ#kpm;_qMr2t+S}LLqYe=vq40JzJdG|seMloA)R?FCmDDgb(f;k4gRcWz3 zCdY)hZC8;j&U+b(!3uoB;yfN>OO%Cs7tFOfirH}NCAx{g__2{iX*sYLSCOx&{wZ$k zy$dHRh;TO&yw`%7@fb#mfjPfY#syZrjw#@=!86RQyrXeBWoO|6nhx=tdZDw#s9)HM z&4P^zY-+}fiV)krA+$NhU5x|MGX!aF)G4$EqP*YcU1Mb9&C9CPw0tU8%o`dAHgnJJ z2Yau_?I9Dm3z3WJt`i=`hAmIprLhl}_{-ke?}RL>J;pyG?SZ63#(X>y2Ft)8J+rUG zyp?!kp{?;5N%$Ort1i*;LMHLvKEx6LV^slk&Y_3P0nF!lEL*kN9HB9AJj|a z+5Frygu?oZ>LHXy5}OmLk(35r9WQ0|c$_fH{5Er?3C+sI3utKu7NKX6#8 zU)%9aLe%rD6)Cnchz$h31olHQwp+5Wg?UquK8UXX6!@@t(;szUmgP3YFagvqFvr3m zafN|?L|yLuHw!=)qHfKrG#da9hD1@(0i`A13a_q3(a@)faT{v{q=wW#QIG|a#NgEn z1toPHkK`^41OiY+HT>T4G8kMSR?usRB*b3?8`mqRC)wWgxYT(m0DZ=yyMXLdNNYiU zU_6-c=LpLka)hj?zLY&Ri8cOaQ~HUko3z)67Z9ZLE=LAa++?6>5b_0I!Vn6joCtHN zqHb8D_?LeYe9!f;6-U%XLy}plu!?Gd@<1VM8<^maCd?pGY^ z9e!idZ)WRju?mgce+l$T0kPNAu}W+9h4#l~gr(6efYZdX6fdk|3)yPtT0jmZP^^0j zi#|dm0KUMB3n6P3`j#v!%q8!{Dt`0kDh0egp?rC&AVphprdp~X!3y$59RVm*9eLuCYp`xJym5 zOUSfWsJdm5)`SpN3vxA6+Or5DoeE^o2^SCx-@m|n@A5O`##C#uN07bbN${vDMzV& zAcb+4-Yd)m~O|?&)ulM+)z8Je_=0AlVmrRJN9^& z4|K~@?I68O92N?-)7jEmJMQ7HPt<%w%;Am%E}8MC*%Yb(IG*Lm%V*rLfKnWVI-6MP ze#0wGvR+!1JXrGKO;Oe83xtULs$)o>46{xi4}u;%Z-v219i_AQe&4F-wRY6yO?^ z1m{l?j-32V(l5?$sAx*Fb(Q7;16@eCKX`#_?4}+{)Y4g(D!#@7kC=b1j!lv&w2Mtg z2|(te?56}2*mB_XFH-zV@4v*Mg4;fS6lh=Omoe;AsuK@W&1fhy`#5D+gG$Kj^c;eK zM{My8Z-cVKfEuhkOhOtbuF1dWSwBRqaat>k+dg$6;=~KuaB)F1}a#rRBkY z#0%wAD5o)qfAr*Y{DY8o84cBZWGOU`&BlDK1$q_*kv1VXajzY&*>E}2uOEoP-RDeo{W zM^Dy&GJ@%<;xTdsL&|~K@|^roGoZNQ8)MjTDRf?t-Vg`4m`3*bjhIsNNRx$6FLD#P`Y&1Md_Chh_*+ z%k*k<56qh6EcIh#N+6DT20k z16lk>G)Dx*XY7^1*}Q|cAL4}w74nHFD=(4#*FsQ36Os5~=Pjb8l0%vPwFx9!6NfxJ{|&ghUwXjxq|6 z9SCAVm5c+5blC=nEdy4)O4h)eTr)QKlPtBZYFj{ul$4#oUj=sfxWt8P@#Y?nU!jA$ zw1e&pH>e)jD3OWKR2txwL=2sIvG(x=>|v*e+-gI^*s#~_FYjw&15~#1TxKRze9oxb9o17#L{4oWS&P8mPxmih|LL;_H*X!^g zWrJcOpNLlbo?tgi5NZh(;?f zCy}5vP*+6N@haWIhC=6y9gRCdv{b~SndUVl3aVVKKU<^doaQa9NLMB5IX)S~D7U76 z(uf`{ttMHPG%F2NcVexqhYav+X>byQ7 ziwD}8K_7$v0Ipx$vb7s;(v|c}K?>bATHINu<#igi?XoE~qtQS1ITBa zd5bc5OIL#GRGRYqY^nq*FYJbV1$q#PZInkt%G9z2h#&SJgn9V7e9I@N;Jgy;Ub`qC z?*iU_X4i>ERyp4>P<8~aER@nT@RTRvKdb)$17pj{`172T!f`x)zZ^4!{a9w^`Pth+KRqoI86Y6jM&+_8;+ux2UOhbqxd%%2b8tc=;61@DQj_)hmDMIHt}YtQ1N}8 znGZy%;dKmvtLxvv0ZViD9?MkP^DiRlaVWYRBUat077D(_?f#4iwK;RI8JtSrv_)IQ z>`Tx0C2Q{^#9W}IdoIvT+_W36R&-7k1455!T(~QG%YMpxsmA4rGhM5v9?5YGV8Wv?c!H6F+zY+VmJ=+4dMK7LLQ? zq4q)BRxgaIXJ4Xn72dMPE>xm{m3V;F0UPorS0u6sZ-O8j=<_YnhQ)<$0h0Fz#1iKx`J z;t8=W?~lL*QS1QhZz%pze5Jj{^N)vS*^=JlQhJp23Yie8^BS8RXwy*xdv|itKIno9 zH7Kc%nZN##r0Mr4m3&L6dZQAp+^%_aJJL}d+lorI zTMFsYS(>R>e@B#FG`7(=lD)u%QooFK(u9&i@yXFCXVLH$O%$9jdprX*18=|Bu=>%HYd^e6XdW2YE83o7u>}W9EKPUd5eWfH;u1Xo9wAMDsalDyHvASC zLCYUdvn5B6T)A6-bpGbeI}fSdVT9Es$+NUNQc+~TY!`?wWKHYT>SB?75V7BcqXyaL zbPKCX@?h-0#1I0n*=qI?MXGEc(hW!taF&s%zYz-`2e_hJsFeU#!OL%=4OA}pM8ot% zu@^Ao4ihGyP_3;eP5AThW4TpnUrZZh8eNif_B|jnJsG(i>TtfiuF=N}0xT=M^V`6>2A*Q(U z4b2M{GZ!CBDQ_*Dgwe~Y!TW-=H-r4nmk+RwbvHw?d~R-G(qiPKKk>={Xy=hu(D28< z4raw|?fgBBKg|R!t%yJ>=@>WiOnuU&KB4@lnRzMRN?lxRy^W;M1wD(c4I?XL*0mp6wZYJhT}F0dWawQ(AzhSi?&yp1!7!OR?;(zLm-48q z1seK@MH}p~KwE5Wbr&f9O1Vc4{@{>ps)s6c?60^tuIx6gCM{8sm~`Q>X$x&}A>-(MwUQvITE?9_JRN1Y7w82Suay~=QjfYr& znD`|ZEe#JS#TLFGpnFoFUL}NZsnOyj&m<3Fq~|eUgrm&ShQwBW<=hL*B&`bmV*xIr zGEiY_8bF3eV>wfU{uTEAP7}g-&p)rnS<^iK02XN(2e`I)ejb1E&kx1uiq=*5mK={> z&M|Olv@lOFK;u3UTwhQ9(d=0d2nyufPNB#weZ+dtxZ{oe!u+kW#Fy^GK%+Yrx*S2S zkAH}&rPaZ?ha<36VWktMc2z7(>~0oZ;}h7nU8$SWnM=2mD#nDkl@xk_7-|#q5~l1e zN&yrhpn3BxAavAE_P=SiVq;YJmqL_Z6t_ZM<(U;+W2CK$arWLIO4$XCv2xvLdxR3V z@KPqtf0z+B`(Obv+Jl%Ft6|tHEhfOMg@pxHL1!N`fosuY1|`pddJ)Fd2v zFI>H;jJ@pQ3-YQMW#c6?o|ZJyFZWI zOv1KvU7B6y@;`w5#94~M;R+kM+o9w5m}X?so}rg-m|D;VWdUePeqW$XJ=G0lwIVBH zk0B`+-r!WDKow@x1#qw+3xtri)CF~0Oz`K6s6vQ&dXDhkgl_=18=JyX_GEB%4QS5P zdr^Seub&dxzf9I6=GeD+aafO2hvvV*IsMFBJ2*~B<2?Sq9b=(CtrHw(Np~J&{u4?) ze-qEghvImf`k)5)F10TdgX#dkZUE|$h3MUhErl`J_5MgoI@e-s%bESBXZE5?dBsKk zq*MhT68v|QOd%lQ>FMk<2H?0CPREFJ7Zr_Qw5>Zh%yJoQS`whXLlj;!l{zJnKTIhp zhmL@z6lnq!x8`4}o@4~ym4G><9VIx1nk*2$S2ZYJX4EHvsk6)`7S8=e%E}oB#;PZB zc!l_VM#eTnMeGl<1c0a!&ob$aTq0bBSV5%@mRSuYkbo$W9O?M3xUWU*OWa!g%8It^ zAyF}W%2Y(l81aCT?6ji&l{4MAVL}!~q7TUw6&2U0cKZ{|sb^V&D~`hNySb};OUBzz z+^P{FS1A~F`a?MJa)^g71PY}PL(J`TY;nlt@jd?8fm$K9LkYDiy`cPVaNG*s_H~5K%?pabY`8-8-Jr~HDX8}$-iKh}rQrQy2Y!)^*r)M;_dr)#NOdBDe@OsmD>P zl~&pF8J4G&!ec;teUDj6Z|)nE$WD!5vZVh2=s{PsG{wYA>T}LaIZ>l1B} zp~%QK!&_#B@cs`aLYm;TiQZHjPs?L4xRykwP_HWd&CDa<`<9L?fj2I^!N7lVw%D$Y zs4rt>XeE_xDXuG1B^XQUktoSW%d$)pQ2GGKsQkyptMHUxGN)S zw*LSS3_8Kn?pL8HlkgNsh zh@(NqSOVZ;jBwpT$M-zLf*w;P;fVQ!nul1prXxXcG%sl`g4E#!;cE(+2&WbgPR15& z*OAzxhx=fH;fLzeX{jjcy1-(w+A8{25OCg zuc%K3u_=cYv4X?ni;O@c<7UD1UBxcfcs^rDNK>z*A#p(hoQ_bU-D^aKRgeqE2oi;l z`=XMUFl;3r`lZRv!Q^V704ZXm5Mgn!tt+vH_?LWw+mHdg6eBu-+A$-SadH@us{BN# zqvkBsL)#P^0l#b);0l%=f(tM2wIcE;ZLAH%5PmGiljXXAmJR9VT#ERRG)^#;q3Hhr zF#)l@gnUtXIUSG~@62=rpe`zi@o;0Nenm$DxA8s#)o;vy?Zfzi3uxI)EZ7C4J|&k1 zY^r&ZiWC+=0bE99*#7KB5G3*(>r()|lduHwUcop+Ns5KKh7$^nwRDPjJcgMpPrP{6%v3jBIHhe-49fe0t_s^+UNN2=W=K%2r4OL$hj?eI+V+rYH~NWj8>4fOYj$&j16L3 zpv_*z4j(A>UcmPl&jru8R#Ewc%Z}gT?I;QU{{Vyf^Oxqot@!etKL>>2_&EGdndkoi zFrnuj&c8l?htWU3Ir>j2(eZ9-=x$y3PcNuUduQ!NzQeOaqk6NppldNf9 zP=*KSLh)<;rF5osJk)QO&U+g5E%j2$lmtV`rtGC(x!2=wnV~I#1H>aX9&&b9DD`vR z2p%FKZOe>7o-@eGKLuvNEqH_3Xk&LSr9VBEJ9BV zPb!P^3bo?>OO1X8A{+T^cyn((N*XyaZ6B=U??jl^JK|l4c$l3XLOhr$aVm%?e6iFH z^#kHsd42^-=Gat&dUrvaXcfOPXAdg!U#|7Bp|I$Wja5`)(tIe(rS}ho^e+RZ@|N{{VLr*0<^o#E%jY8CRAI{33Cv79EZn@lYt* zBl#Z@y6=70$i9<9v#L%~V@x5?P_nW7Lk+RkOO@}$D-~!x#T8TK1Tq4OXPI<$C^ChC zkSNQsfvEdU-g$kU0t2v=#f-X^s@KEFRLzDBl~%$Et%9P=Q1uciYC^takrKfK3dA?N z+$tfjrgEKrqEi_!#7LP-JOVd;#33AGq9iR&lcr#V20gAvt;g|jMO{rlg0X+CL^ zxfT0oL_(fiNw*@cKzslcs1j?!TRT4GAmv4uZG%6gJhcmAJMg5o_xJ+0!5&^Qy8xbu zdjm~a6@;Sub{T6;hAO=sAW|mFu0oEN!C@fY#rVEP@#w8SBb#XFBdcLak4U20>nt2P zsfeG!JQ&4(;wAAG&n1#a+h9f?WHl;dkC@zdqLb9UpdR6|wx}-#?xLYWahE;>06215 zmua?J0k5RA34n-Dyqg4}$h`paA!Vgg5?QAsAh&oEz7OCrZ{&_PzSaAOPEdlnOQJNl zDTs5P>R?f5Q`{v`WrY5sUV($>RBF6LY~GtcaGZ~bt%kSxNZtZ6;=clEXCj*GpxDke--1ic#>|3<*U5jV!M#m69UK}L zDKJhkEe+ns)D*Oo*$sAPu@wzd#Mh-{+hl?6SLBT?Yt%5TSVX_(CAdmgO23HoTC4m* zDP|!9NuZ(f&FugqtYuLhgvQ4M+M*5;@#TJg2=j`2Z;72wUynvc>a;vGfcRgMY@s#K zyMaI`E4|J{$ZlVM4#S?V>g5KB+n3bvAZvMu_?6;~s5j}AR4X7CmYxt`FNW^^AoE6)HrZj=HL1%2<`C{IC4I}QdkQ7w)!9s0 zXprc3VKm3!#Bmuf23j^Em4{=9SfOKElAv^ccEppG%4U8xVzveqSYuc2s zUXo<^%Tmwt6R7$h#BP?b*yO2j6j`KKtYaLMo+Dkx%vIue4-;*`RspaPcltw8BLF?9 z>MHq6_UvpG?Hm9l`DOT`4@Mu|NN>af*nP#oRue-m20$L1j=bKEKvPzZ><<7mKK}p} zvCVJHv9h~9+p9m)vw}TXhc+1}Yy6nkDfuU^xVR23+fy ze3jU#QcJB{j3xfWL0NEpiA(2*l1_o-xEpspASk?0mPT4+@!dI4f&Qms2n^TR3IaQJ zp1ei6-$WK;y><~sE1v-pg%;J0{fsgPuV`;PnuWE7d_eS=D)KYILZs2r@e{?>^USM* z#2}1F)5!LcEqpxx01QR3!8G}bhPI4o?&4zmmVOAhQrnBF!J9TK@i->0lKHyNIl7eG zd6L@$(4X*vx`3;-aDM?AYmqc`zoHIa9KQq)Gt39#-NYj2QT7B%(>&k1mj@sBB6ojK z3+=zb$v>|;N1ucG5`~}GmuP4|o+#(__{(oXaX4pB-1D5j@D~ro=Rc_`%NZHN@pwmN z8O6D6w@BKqn(EJns06hNuZ&|WxH2ar2NzT4nM0=P({5M|d5_|w!lEdsS;*YvGyyazBE)i|KwWf*AS0~itP zMX6P1mS6jWz@hTS3Ks`<3y4tAm;;ew%C|570J|Nlbn%V$mrR5@xO}0&Y^PEKXV8s{ z1A`2nc)y8DL!k2zEnd`N{mcH)Hj{xb=fFfT<8gw!K;jjpfHvcQCLF3TpapxGj~zo$ zS5S!?t72AU3M}ygwS)lv*%3TfQnk4IPS3@Cz~uWyS7*!>t7&iBT~$H_&=fe zD`3BKfN=m@_(3aN7X-x}e8qa5Cr{k!8iyzNBc~_K#-_zzGtMu1y~Rj!6^vqnTn4P1 zs~`l#@8!iC41ISH!jthT(%A`1GLvP>U~R@X@rw~ohN9twdfC-P8)?~PgN=}SzF>nfFx zh>;0Z_7#0+j4DvpturjPPz_7Uo9TRh7UZk9%MmIOx+V}GCz#`cBW;OtDypU?$u7N^GaXp~F|EcL;=gS7jEjf;EN!B3T0J zErk6_6c3o^wLFkB_4pY^C~iFbAJCZ=dgCD3L^T0a#DU}#`4Q5XB7m8pctwMdy^oos z>+A8#DqKC7n*$#bl8mfhq?yyi=#6#tFnh7F5srRF!~nC;F~l_d#nHd0O*Gi}hGNbW zos@hk*!Jxg>N=rTJ|h4=vZgFKQ3wt^&fwdZ7Rt7HCr2cgDrE!2XMo+q1+O&-_NrPl zV%G0aQq=w8En8cLvXkvG%0Qg#5Z`bs)9NQlek1OPE7S6f1avUKfvV4l{*jGD6%Rr+ z)xLU^DB?Z*PiV0d*hE00)QXr@?M@;u2%+^a4eAfCF#t2y%wfBF84B`&BirAm&Oyqm zl7?}KHn6`W4p-Nq*YMXR#eK5>06?|vMqYq^VOV#y@g9ZKk<|YH0v-PVS@38hc_D>E z$Q9UDq!y1bw8WGdLr8gsM*f9BhP|7O5txe&Ico_$iNC9r5~)_+$B9WO&@dfq;^i6u`5x!Wwa#0pwXD(j01LA6kP5hkPB1l0C?me0v$I$%O!}mbN8)N*cdN^sbijANv>NGOt&0rd+S_ zF0ZOg2*yE6>pe9)Y1o-C*A~R7bV5lbpqJY zUxaEe5|6`YbEEOJdThM?k$cdn7dEX%{W5&wZ~hJ=qm>|*wpBpXZXJz z=S=>b^Zx*Xa-Aof={kOIaa#ENHVJd$H{>k&sjT&}fjC2as0elo{4jk6yho|h3$~Gk zOhi-Rs2sWo6_sm#$h6X%HL!V9JP`J@C0Kk$EXrF<5L-}J+$PBB8?~9z8H!Dn7EP9y zCzt%EU>GUeQm@j~6nDZXHXccQ!d;R3-Egg!eT__AMU?)cZ-X22Kd*$f>{gXI%mG;DSTd)nJVF{RtxqY|bNneteU}jNbdYxUB(B9-uDJgIQqd%QGwx8iaKta_8=>NV z@Q(g3>4)mkTcs^cSa_^<1#}=>*6Di#&0-j(9rX#QCfsD9GU4XM$J7!+4Xw2Zl+vyj zC|#&u7u2EgfSx0E==hL+0Y`!!iIgqY)Z^Hd(Vr^766Q*`Obf|o2U40>1HV^XfOxRi z+@{8gn14ahFGIYpqo)Lt{{V?kG)BDa!EET{2!+*H*@<2;){mk5J`@(q=8$arRn9fsvF1&ZMKl_l>GonQ2fpbbJ9 zWE5`Fhh^m{O%da=D_wi2+pU9qLmk1Pfx`DojlP%6(jzDYab)1CrG?6wcP?6M%nAiE z+Fi!zxy$kM{lfs3Kxw~!;6_*zha!w*O8b}J*Jh){xocjf0ixotog>CQME?L7+Lw?Q z$ihXbSUrsHAq4XpJ@Fll&ha9~tFsqTSJH2_6mQ!VN+l{*F zrLk&!Mrtk+x#lnyiI8>_7sR_Tpj|~xdWquVcF@a|J=sx8(smn$t#M&-ULR8`h2)o5 zfV$kmw@(w;-zr!>7RTVajxhC$d4)hMv2cue4S*pRs8rg;IVvn_?Y)S+^$&}OS`G%o zxp!VLMeT~rSEwX4MZsDEz_qyWsZ_DIDHEKyECPJGlITfaXdh?{d5QBFxMI3Az9F?h zwg^CqaQwRsa@ai?R)UFO>&kjUHd9e7!5f|3iO0ZbJdL-|vIXiqT*R)i8W9V{{839x zYwjE{%Ow#`{Y7xnxf~2`#9e$T^EU!)6OmOfA9AIYMDoM&$X%WkY4r`*QqO6Q4;SVT z#D=mfiRv_k4++?bf7~PXb6zGb>?@ILDy%E@HE@z6B@6e&H1>@=5DKDNhF=lR2p(Bf)lVxP zGnN`&geI6nvm`VE1TN4=U={1srPqnIekU__P5CS(c5$^tHB;+6H1V^}SInjR z{KZ)>Yw88(z!U}K*3(x@xeXl(>-TYZ+!gmKpdK8XvAL|cm{p*| zmAB-stxBUFUDK(kwhmA$%urP*ytouygKrN_m5?g+PY$a+CCK2KA zQ;tdjwNxtzcW>$xg5E0s02FA#yM9qncN(pDl!@SvVxVj#41HcBcI#;qG*Jmzjo2)z zAS<>oRHJ!N2-G5cRm_kE^{9j?_sNtRhf>=ktf5SsZoyzLpVS`|CPYdL9TnauVFc2O0CRV!ATx>|uGYDVLF=NZ4^dMBcCAp;=ziiE)pe-hd%<4c_d zu(SUy&g*rZT5E|RS%8y`XGs>zVXN#+!EYw2(^B#Zf}o{h(~6q12dLwd7nud9O3 zme=tRN}fOxr8+!~2m_*QM3v*jQ`8C(D`V=!i3T&MG_Yupp5Jav=aBteI8(9ShSg~i0Pjm7>TbBCrtUrCu<%#V#%47I?71fTds9IZ8Y|Vyybz1i z%o$fwOGM;3SnT?m(FtL(LaM0c%F|C319b}p?FXER_Y!Me}DcU;FVrN0rXn>!{GvM~O?;TOZQ!MMxQSCTX_cW( z5lpEX_<;xsfr{bEh~zZACR8HBU2Vx?8S|@*{>|+J4BtWNj=csjzp$mob5_Pz4P{${ z;utHfvb9qFkh9oo<53ci5GJPEej_y;w7E~)yD&1D_K})|VDh1p(b;t{J);M7S%f?m9 zMQGS1s#WQ*hZnR1st<7-Q7us~_xKN(HxPI2Qn&VN&{{1fN+JkE%6JpaF)x4f}c7=bj3D%8<#9-M;TQz6=B0Ury<3z3Qqq4ye#u)n&<`RjM?F;0{}F$JtPMFiluNK72)mxaYhYgSOXBhJz!xjAxoi?nmi6cOBQj-LJ6|edXOc@g5}CSW&+3@ zQMICJsovd$2I#bXN_Km(Cl%C*5m@@b-pfI`?Jd$-cjiAR+j#~m5H#BXpS%gugh$Ve zfu2hO?6_YCErfbM5ZXb4=kOWGFvS;17lI9EATym4tgn@{zM|b(*fe!0@{Cdmjv>BM z4HXo-8b6q#Kspc9SAgEkh#ho!EZ9x89a4%s#;%(ruvW)3{{RT}N5aI8!Ndq(bt@6E zELC5q?O$ZDy!kl=>78<7poPm|fmg`FNTqi?!Mx#978%0lL^HC)UwaoFzYLZtl+rYL zhKx$>h{ISX_b_lgQ5w?eg#fD7DnQ~uA0W-tyX@{`Px6+wjmV@B}R+(Xw0))RTFax9F9p7WEga$xI zUZYUKqQQRPjlLbhHJ#}ri-KPcc#D>|LFQzFR-Z73MffHNDaJ&k^&!x$3g1yRx21|| z_0F$nh;VMf@f_Taq-ZGo%$-|q%dH3>SRTw=)+f$DUlF$&r-aDHX^O-YT^gLp1oi_6 z2eX;w1uFn)uQ8g{s3{N(421s3g2l6Y*>6ehhf47FU@xP4FRQ-Tyu&B=C@{_*~8PXwrTEs$f_ zBnl1}QusZA93j#BfS}@D+(I2_<14N8L(WS2Qfi=Ph2}1GZEisDEzCPy1nx7QNH{Yx zP>+#vy6g8DxTV8<3{I#wP|;IIn5cSJs16_Wq2Ap-1_F5}ixhSGK0rzOD1M0Zww&n= z_}V%_Di_P~8`Aemex>rbgbsm&DiVhjQEln*7Fk!p;(wD9=a!(~QH__y=O<-WfEHJ* zr3#lWc!OvGdmJJnuzec*5kM_`hhf5)L+k0 zdi?(Y;Fb()K^={BGrf$z{`iYiEJJeUT=`~?Nmu{_(V2v(M`aRxnc^V}uGA{Ly+df@ zJii@EEJD;CR~yl))}`mPEH^$LN{HXmyYTvsQM#1EvM7QyyB}7&mRHeK%8}QIY_^$M z%eZiPi5X3_Xj9TnWD$QKFeu&H`wrp}_Vo%vzrMrFJO&V^#h7kBH|)#(oy@7MdAX;h z>)^q>+pFmj`Bb1#Que}KEo7{@wF$RZBeA=|mwXQ&aoa={*-9_vD_14c-{NJ!j#?~X zrRTDbb%PD%>^RESNN=d$d9Sar&{K)TXnAwo@WQSe)PJmgbsA&DN@*-|RYhC_i^P88 zRuNaals#!O`V2GmwLu6e83RDXY~k2@i`T^3Y}h6z@iNc? zsyeCd12JtP_NE>2{{YEk0c{lk7lj9NLT@g42z?a`hO1EgrHqX<)y00Qp=FaNlm6$& zlZ4=$XBhFFCrqMyWm(LWN8lLFPpQQ7olo=6DbxNNr_}TOXw`b3+9!nmr|16w1pfdx z@xI>53vsDfO?IL6r*WM`aq}pU^P3GsS|(cTe=IBTPxDITe5SG_Du4&4E+L@IMIvEW zk(+2&9f&JGC_youG1vxJF5vdJQolqH7Ou|okURzKqyD(aJ@YV2$~`xf?+Pequ3lNj z)NYl?eat6ZNukBBDMB^mAm7qMfkRI+j+iy_(_b*zt=NfAFX9iK7b!;Jy%BX~&o*Tp zXUkXPuj3o3>HAEgEr2f6SYYgBX@E)WCH=S531*>S%ELp<;v=z!{9>^X$P^;nA@rv* z1V=^D3{6@2hDf&0P}9Byw5nn3Qrva|z~w}d&~BiSR4PKe(R`H({imqDLv403w@ONU z1C0Xz1I#ugXLv>PI3m>LX5GFMOF9k? zP7N(>o^SUpw0!ELOWUawKLgwWn|g#ZHjvm{!^?08xLEWaA)2l5l(EHE%&Sa>g>UUF ztfm>be%D#of)h4JoT_thQ$Lbv4-4$ zE*Zp8r~|)ofHY45612pfRvW931AWNzT1mqhsPFRtFeSi)XZvK>{?MQaRx*?%gOgL7#6&EjiRjum#Nh(@hJFW_%A10o4-+BvW1gn#?tl4h8xTvRPG-ULv&Z; zooKf&;~4hXt%8Q%%oxFbWpM>IeiW#ZmwJ?+ddbEO)iE?hOBwOTGdNNI97v zGIWC0v!VnlwLuLjGhlrY-?Azz^vfZfM*jebfLEml+1N1E0n)STFY`EnjV<@gHc6*S7G1qMoR$gkvB5#MG3r)%O=?1C7#^p5*pP0 z^ydhVYB(KdzGZorgz&&I*k$3&*zW6oA^fQHxdrZvQXg>x7j};3?n@G}^oD9&=|r@f zfoGb9L-OT)>jK!j_Bk~$DO#!7>Ff>-Lg<7P@eqS=V>UGedCq*s3u5KPXWSZ9!thff zUx0!{u>viJ00>h^4Jq(d8pQ*Kq(H7361$fxUUq1Y>m1eLuMhzhFckZO)qGIB?L#s; z7DZZY7TBbvMC+SxG1w>;9f=^(rpZvr4z*oO@W@+qxu4B) zholbBbiY#)jsOJ>h5|@wuP#{hIdZ#BMisFsafwZjJnvG&iU*if04?;0?IxzD8XyH) zRpV+7SQdS!jQpsl<5fB4QDN%Hxtie|mRv6yb{N8)s5(6jgT*B!x5%vTxQXp{A5fzj zQGyu<33-ynmfdHAj;qHWt1y;33Cbc55ECV#`h->RL<_KCPKx3Sh+cMA><2yU=e7(b zj;F(HR-X_^u84n8m&z^w0Fq}U*VLdOI@H*7BGG&yQYYiFekQ`c(Sa8b9jL+*E^&B@ zpE9MK43ZW7;pep)FZl9K@PMS=?!uvSkT6-TlGf2c`^<1`i`@(^~|(>WUF7s!70qlXq; zv$fzIx``fiLi$>@PO!g(FNw_;7c|HhSbS=HS@|2o zwJLGzdjo|uPgh-rP#3~iyuUX9um!B|+-3n>myjyUV83h=)Pa^nOs?FXYJk5Itbl^- z4f$JqLaEgyH-sO=YoH%wA`;M*qM1ZD6tDPD*;ri@=G04y2uuCTNFbhYZbJ@AymrZ0 z0e9s80LZq{*yMwF^2XnDfQAqR^0=C<7Q+($=wFyIybu@l36h1dM%B`r4g|4p)IUsg z$#=7BNJJ-Y_X_5*D_X@ zQjI#cRpcE2q3w~T61YkA*4>7>Jij79|n-{U6=wnml z41GbS$jPh<8kQ}~hj<6veSc|4pvWlKxSn1kzuIwttc2PKm=4z=CXjI0>r-zbUbp^-^Wo~3bD84AM5LOjZB zBB=Ue2`wyC00wpT7i#qhAp49k#u=ySQC$MS=?I}@R_q8?;AieJpf8e;U4huMe=6(} zC@XmdDRB&&{ctL-{KSKvgsR~(n=GR_sTD@p3T^~7Qo z9wIIa#Qy-`M^lz;Q_wt1>imzml&Wm{neu9m%5d4z>&`?6MVSiGm8!P;_;<4wLWr6* z;t+#(Jc8g^)pW#5_Kj%jrW6PInCqZQ(e(#eGbM)-BJf#e`j^039yKYtwp&+7tTYRMMJ!S-%Ac(SFbpHTw%y5XXP}K`ABpFZ4b!PEf zIp7*Wby>01D3FTCO)*IDY;8*S;o*oCg{PTONNsF};5)O~K-CTv{XoL1`ejjFgXUL~ zcz!!W`DYAemO~OjwnM+jN8O!ceX&TGyuE=2G%UV(DI28-F11HGjC83^u&CKYxBMHwF z#1z)OLl@j2hGB=2i!<+CfN8@bO#r*NZS3_th@+K7)G>L31tHy?pu?b6@`P34L7A^& zc!K*Wf^$RnDzSEmXx_FUF$Yoz8noJK3FDHOOH80YaFzB9-&vmHa|0o;au`ss)3;YE z?N+=9;+39;V9j-JGb~?Mv2P%Qcl^qsoz)Uoabb$5fAJI$wDzow_o+2PcLF6)YDIWo8hlr-PEGTj46; zA}6#bs{*`ACbJOC(3$=sxt}kN#GdNH1?A|JmW5RSV}QJQ{{T@!qT}KU!m;%^K8N4L z4^&unjYU7SOH5S|dV=0fgXsY(d?E|N4hUuy+%{B=X!R`(B~iELGV#v{&k$A{8`J~D zhNUY0U|6D%X7EXPp-)%;0B~l47Cp<$zMP2HC_bPQ?x|H@`G)(u9c}7=o@yK- zV>)E+e`;|MM~Ftfi4~S2b06gV6N$u?Z}Npu_|7GPFFttf$07ZQc@{qy@)A`?A`#W+ z?*kgeNeJ+y-|ipMcwtIy!K+OEU=u8!ALz;$_@bD+&o;z7Yvo+nc_dv=ef9LK;-jR7V~tY zLJ(cQ`kGd1Q8Y>sG1;>ZY6{%lXn4XfWn>{ zg{wKaN)w}ffZ3wOTvugn_=Qpxm2)Nh17O`k^S($SGAOrK2b6w={s{KQ#dE9ns6@iX z3#Hn;hyanvQ!$_(S+UNB+vX4<30}gp)8MC4(A~aaQTm0h#<>&Dzy{Sd%&$&?&?1@noHK!kc?l05>?k2^bL@bdk zCH5p%ZBW)3h?IGdyh?QQFIPt(Tb+p=jLRT0tw3p!=1Y1b@n0yTrefXdt$a!cOH~8X zw};$Gr?)(<^e)O90R8;V8&Dr#`z=9d6TOJ1L&_is`%4qfAr9G-abdYjQ^*5#W+^zD zE;dL}st1fUNEK$f*L_9)aYo-pHO!Ybwjaq3Ort@F(=X8#s5r7a(_WY-V7^GWC;s?| zxZL`hSeXQs@G#UgBdmLx`sWYC-o1VY3_ptt1X^WTD^-Ub+JB$(Bd3Ul{7Ye^pl%yy ze+^&@@cdJ_R1Xm80SKQdN53C|SA+$=(i6fXb0u=>wJkNPfg~Fj5o>2we7QH&^CnKo zH)%BC7g1%~kOBFKDaLlsq`T4e93WdS>NGEweGqOfluKXC6lw?}(zbm@#g#SURA{ML zspOuPCCWXw8!4wF%UCTdt6YG6DK~e=%MN+~eTB@)5U@p09TnBWZ?RIK_?}7Y88sl)MDXb6DSc;Su{FW{0rq8STtZFp@27D;PnkC!YZ2V4=!5KEIR^OO>X`m zzOMoOR+Q` z1{DRCuzJL3wh}6oz9cxr+p{r?k~Rhs0?IrS6LHqMd42)oU44c(@H3rTt0;LA$ZoxqWNyTr1_^N3`Aaj0#jW79S8Y)-Tx1#(<=y zml~CP?lJ~r8gH`4RQLY?8J4D4Jwv8$)4|voMTzV?HuKpqn#s|~nYHFn1+`2QQ)j+^ z>;P_Q?jb@xcxHJ`zVOsZ)#(b#jmlNphLwdoJnYDAk$+@eIT=BBFWG*;?E<-G6L>_bmSa6%v7=<_rIJnS>)wLNX7#8bFH~o=2LWks<~oAwJ$5I?{2)cEZ2ZfTv;9uZ z{zw*R3$_BafO5a~ZUQopGv=keVQ*oOs8_pr8g&X%h41%p`$?c2 zc_W}&s%P^lm!qRyojUUZR4fW%zcUyOQq6dl-Kszz1hq;30Fa&_p^~E7mB=^NMJmWm zDv0Yis4P8w%fWjU<|HU5qbzz>%Ea5M`h!2QOb{b!dO*HoWiQkoU1Gi^WVdW6XYF9u z6}9y78>ZDzMH&*-!vHK;@sQXSSge2nhj^7I45r8+EefQo`GEvxCt#3M=$}%)T_E21 zfUH?XSNuXetdz06fde88NPKyk5l6$=b{@-l3*hq`=q(0#4j_K^@))?q{X;`z8zh10 ze-MFtiSS$mg1IX`PjPY@2GvC`FGk^J?JF!GWr8K0QtGShQQ(bltA4! zVT;P^vamN&trHx9V6({dej~{3R>F&Oq#)Z+q$T{pZCg15}0-F1mX9I_)g0cei}MFP8rOl)sa zDD*e8s}nHG^i}BWq5dM}*Db`-P5@ zfodAFdTS%KKW`8xVreb-N$@z@7tE^KLr-GyS43G%Fq%2F5{cN#Fp*%^U?l^FnN#ah zn?4|rixbSN(cfu^Q)c>vM@V&0x4{l4g#>O^&4GUG<<<&tec<; zfJz0+Evop8m6Xx`C8_u&R~2f?U0=iy@;tI7GkbPLPEO@t%oDEa8%u^3)QiD=A|leP z`~&qKM5)2QxO^>jGSVsr<+2iP?QJf0A72_wigf7BWl+L&w$ z?My&7@ReM6~5Mxfnt4J@&2@E%}0gtnl3UbPFU zKrfn|*?{l-!SYisofwQRA9Cb{&}ulR3OpUn4H^hH1HkF^dnG$p_$c5As zA99Zem~Ki-G4& z=Lys5a>tqdAIC4v(sjQOk()d0!E5Y*Mni{nUS1 zCN=KjZ(@oZA&p(15ODh2+~w88$)jLFxY#rxK;sg^beRz1&!iUlC3#Br2z>}@>e1@s zyDb!c<&l-$Lz3%5IdcMCEi6FJj~51`a)m&aQSM(BMyn@Q{3y2KVBRYPfD3Ml$dzw?sQYk zAkBh36&1uyj1@|(d<=a^>k+RXs66h6*c-3Am4H8`4F3R8wz|`;K%8uC*v6#0Hl;&? z9zle}aEz$*B@5fxbS>(mFAHFA90pGhHG@z+cp*nw%o6Da)u26NZ$B(_($6~)4DLli zYo_4Jx>RSH{{V22u=VBwGvkD>Eed+LPN6F6Vent(5v5oRSU?v%ES?;XDcH({DDfzT zD=D`VawZ|A9%2b*<*$DehqdcbEvgWW@VQo1Bzc`_Rw;a5!(szauiG7LK}PN~l*5cAX*J1jD)Jy!RmS5= zA@G;zHYR-(-#>^JuUddb?b|%^47=tdwl8KdT{jd{F`{7EQrbVb7V(4qCJ3$-4eKj3 zizO@Q-{VJhU3s5cj}}EJ9d!l2XR3!AS^*bn@Z4k}>LV-7)$%XHN5TGKYrqY^+{3Xx zPPqc=crTom)IKo=LR5~&%pNU4vGO4ACE2i^X`kvTM6VnpI!Mu%4_3?@hp(@s05`h& zTy+2klwX_B*p*Q>SQWjE%M=!-I^7KOE%k>Za_IKPpW<&(K-c{v1WhLC<7IIlvRAAX z?*0~Q^Ptk7vn97S+7uwBrLP#_;Jlv2g6hwC6U&MP!(5O z<%T+3c=6&2@|8^R8VV36ryDPxp&_S>k&D4a5v@c8!U5_CE<9m16qQ{q$o zz_JQ!OuqQ0f2U?)5Nwb3Qz@_1BgCrL?|$V;L&0_ZPTSxn$W_POx+e8(srrIFj>gqI z9yu|tS-Nk}s0nHaFWnh#-~qSvfsS;dxAd{|*3dtp4iAo({XxY1p4$%sh(^;$Peq|W zf?sw`2Kd<72tX9L_=cLxT30N#4p6}23aqOtTDc{HUo-0W_=*amiz*VRXf`L=2ihn_ zRTAd0qCPO#aiQ=oN~sJBwfc!u+?|3|+8)vEfVPIeOx;H+t^6KAYNgM6vn8*-1fW&$ zg)_z~`l8jtdpGiWc$X$?4>91&tQ@5<&l7FMm)^r3Vb8!U6&NU&Wb-v)f)V|ys(6=w zt$i%8OdcslR_XkFz%-S#%k?mV1HWdxp{EIYbw>hn43#e zJ#Px0EFG0Q*u_9w_3kV5@8XnW)-7t#dS&y!lu(nTxuIeA0@~y@vh_6ySKPTj6r>Pz zi<$fWp_Z|9op;-8S&3V^?SEG+30+JQ!W=3$lxXy)pYA>;B6&Q)0KLFOK->d+3I{GC zy=t)^iD9}fR44WS01@LmPSF7Hlv}9L=?Z7m$@MGIACHN|;ecdCZi(mk`F=TmZl8hD zc1|I~+xRS+@hxfQc+c-nAH?vqBLQAVsO=X1eL*=lCYX1a08h4q)wcI7he%{fpZo|$ z43}rTFwQBkRYp|cv(}t1Q!g*4_ZrM$^K(HRs#G+C%H>dUT1eBZHi)bBI3VL1cuWx-n1i9oUFQXxEl$Q+ z0#$GzMk15XpZ5-hGC!Ehp@sAH2(X$Ch~t?j$z5)zg5ci;jpc01d#RX8L+;EiSBuSr zo`I_@S4FZFEn3Qp2@PCt@pMcZM08cV@Iw=>k}O=RaakX9?C5|poV4tE9;MY66SfLl zg6wwHmnyDWNG9OuwxBXfhm2m+?8Yjt2v|37&d0^VFrG1{ZF&ceG>M-&#WGb`^`HtFE!^*~kta?I@A#K6&2?}aQ z(o{?as#tBqPiIb3%+XW^8_SP~l`DU7oGrVnv_8WnI6fi;*1#4R2K2juu#GA!VAHQa zI~Md6mVabG6xvh!jiPi0{{Wht;M&GqAYoD#vV?$@HWr$?G5VHSt5UyGnK8?Q4-}zF z5EF)us@MQnyuHW(Swhq<0d5|lUEo%pV*xNy_Ad%c3&`G!aCm;^!Y)NAWZ$s1N*f1drDsnb*0YhAb;M%3};tHz+ zanvn%dx@QQ-fCNX&Hn)8cq2k@TT+hBhb_L6FOsS_>6-G(hMsv~Kq&=OUztirh1q|I zloE;8sY~@NVLzf=1h?`*74>HB2o_HJMLLbeMNl-ZMA<~6c@4hew|gmJ-7SFdSz^`TBtkwh z<-)*~>x}TrrQ4>I+AQa6rAH7p#AVV5`^R=*$hj8L46FXgqd8uR0$xfl=Vb zt;s;RkJB6ER zf8!T&3UYkJy=-HugJ?@fAXF`!2AC#rJ%G_s1al6x%!(yT6mZM5{(H= zYp;U^jm)PpDWC+0^+DuHmm5c#i$`WFB@KW}L*T(Jd>Vo{*azeP0Muzl{l)(P2!`LH zJ0T6FQniZ8hO6XelJws3he%>Zj4=^$)%mB0>6d3X!n`g=p zD(ugmVc986@d+yPI(U{XmR$@b2FeecvieTue2ZK~k+gpktnzRIK!evj7azhS+gRT#9Hqmj9+AODc}W`h_dUalSY+?+&@Y3=Jeu^h+-5hw2r)} zTc}$PBQ8Cq{8v1nPga5CF58AQ_g-Q$!7CPvD0&2=D#Gg5{{WEhna6fh0k4MOu(ber zAo`)|GC)PX2sJ%ffhfLhTz1D1&j=1{{Kg$QHXh4@R-6{rQu8dt^=mSru~u*jy8TT| z^B1J}i~^Sqnn^#5JhP)OORwDU9vA9cg_?OI_E#G<-5v}(k$ zoFOmi3}(jmH(Hh0Hs@nVv%pJ_3W?#8r(-2;+=B338+O9bp4DNW80&Q-!Od%yWSC};rC!MeV0I;Zt=t*(M%WO?x`wXkF(djX~ zadKV|kOr1s*VtA?L!hk83a_AJ5vuaRi|W{YY@k-AvQ~A1wn2t>qfLPcjT%c7I#RAM z8<*OT{$NNtyi*VU3ugKt2G8OknjeJ#Yz1``PO&svm-!j`YlHVM4e)AQM~T>c%jqFx zEEL7;d7kUxsAH+YjrwK=9EO=~UgZD;=z9D&)fRr$jGKf~(vSOzvX(NE*z1yPvE&+Q zvB0fZ#WU^Y46E#C*H9*MBX-pCMnK1spjx(;d)QzrMwt5dK{(~QqF=*bf=2V$k83JYR5rQ2U_BWvy-^wl+ZX*o2>?II&k!uQ)NETmdzrD>QN?(V>MAeKAON;v7oevxF2HsmoP8mG zruTajfN>N>v3{d6qfg-f0CRb>9CEG5VTu(~yo$k`C%?zLWh-St$+X30Ev<&XdHqR` zCup!NmJKR>M-J4mFgb1i0PM%J7Q?511?}+pm(?nvpqde0o+TM@X@?(UzLgT%E)^HJ zP9WC_t76nNIT`PMo}<6D2!~;C{$K>Fc=H~l>y$_>PcqE@1h*Bg78^$I2Z%B?qIFWy zxHa?0g~}5%jMy5ksDa4+&8$lXQ!-ax=@ByG_X^qj>d||I_q^FR9XqwvR`h-J^ERK=2iJU#&o}T36u^#KFN~I)L4fN^*ZYoZ9$_j3)zu$Uvzo1|f{JTnmjwm|1P|-9 zXq$by=rFc{Ug%(KH=biyD5>!pSGYv&!=6?vZ_Y7wz6DiDG`f*xa*1oSSO7sks+qW; zO9Bu%#Gp>>t}e9Dn*L*^5zDt5Ja~(bvhn^PJFunT`j_WQ5vQc5NjewzDiSn!GULN& zzuH%-((2f_64nqka`Hl?__M3H`@+&ej$+}f2bTlL0C2xPqe;f0YYn1h`pWM3l;T|s zFTogzWpKRx&Er#a`}%`iR7N}E2y01iQ5$iBpTpu}CrbQOvg-CL7soDRV0)^9z@WT< z0d`|j{^4Dd^1v|L7YQgonX0XXN@GAoK4JWX%^beXncoNp1vtlP!AUd{g1vjD*B;Qq(kNkPZ5P|{{SrH`kYSC zN+sN>qMPh-i5%&1DF#HYK!RCeaq@z{`jWM8rge-UM& z-{v9o%QsM2R*Q?hnSBs`C0QKu#X&BWH2`XSgx_q(g%6GM_c)saP43Tq-wMr!`Dz=M zikO!BxR<7ss>70{a0+n0<~(~f!GG=n&aVaBIsygAWg+YeNdANso@o4Zo^WX;CbZ%C z`Y>OlB&Jq&EfA~cc7J>DpVGuxc2+-{;^Tdw*?#4}01Wal*%y$R28N1~$?(9Y-7w^I zfBcR?r8)qY3?GI4FT=;`cKiG(rz#3`hMp6Gc+MYkgYaDBirnY%b2a`YgVf?!U&O*{ zXmS@2q@X8$fl!17N*=j z8Q>QRguIHETDFJ)?+JNuTF5^NStx3kgtlA@b`r4}ZYT$PUP*ArOlslmK?otMpkX{t zE7#!M)Fxk2>%7b=KP^_AASWK&e^YR`0rL@7&FLSw%5|tJlGaNXUof0i;{>R2R;*%0 zSTS`5FJ^+`_M=oxl|9IMu26)ndZxoBC(zj`nW*HPd`ylA`sw?8;W1Gf7C1m zK)`C@(~H}uui|P<`0EZ`F;@GG=j!{+sG>z8Vk?dc+}PEy)!P$ZiP_4QAOGuOZ_58TR02%Qk(bYZ-eSlO}H0+3@UaGAHh2^ zsHXNmRK60_v^rq2y>bAI0$#w7i0!~bq_Ec^ zf0T}T5#Yb3H8!WX&;_-~5(AYISMZG&XyfJ+T9nZb)?)%H)>3}R03*VpkkE&kgK8+g zB7ql7<(K#CAsEDZhCW+d-3?_+Dqf>!3LCj5S9S=Yc87O1s)06&-#3V}kEd59TB_^Zq%=q#}) zzwY3$I`)T{Uel+B2n5mp0D&0^0`?vP+9MJdCJmW+8x?}D@r{IdRW1jN_J!JhTrU!MIJW< zZBD=sIf)=tXmVU+eaM77)L&ECk-&C3sPFG9bHt&@*~!oZ1|Fdel^YWvjaxnlG|9XO zl@+{-x^(w^Jghf6?Gzy*2PK743$q833C=W4pR>T(`>O|^U>mgVfVPsobG?vnX zE)t%SEQg9USB8%6DfqW`U!eR zgUJxP(?R3h(`Mfj<{RK*DmWB&9gVti3Z#9!QTB;P!x{zS2G+a82b8trJ@*k*Ia-}P z!?tjgWZL^YM0RvS2{874CYpfxmPnLlC%7z5SWz#b0>TW-UNiR^tpMLJpr~5AM-uD) z--?coM#O6!G=!44u`@GO~Br z-Tt6vhUm2>hJvD-w@+MvTDXL8sFZz0D|K}%!>N7H{{Xl#VW_lvmC$m~H1cL!fZ$xE zF+5Pb#+a#2we3JIv;fFJH^0YT{{Xo{BD%)V{{V!B0?hdPh_P0PA?D@Ls<5FBL0lY! z=<}5Wpbcb1)CcTDAUD!BxGUKH<4Bl1Z|Y<17xLiET8CxIs6j^ZGKSY)SwWHdnyEz* zqw_Mgg4mx^(}}RXzyNS_{vHvweGxzX%d5dd%b(&*v7Ay|J(Gv(SpMd8{^#SD+@^Nc+S(xdCnMNE=&l1Ai{Ee zP9xab_?4IDbo?76vS81^<&x)y=$2Gwj=gj!r_D}NJ24`2pdu}@~6#grQZ>JRG>-P$U4o+p~Wh_83}X0@C1 z&zV0Y}LsPgw4=)pSPFhl1 zNdIGTPZnU)YN}-vYp2BUnFJ6dDlR9Ke54z#1zT)egNQi9 zRCx!2bf*G6fy%HxF_hK~n`4W*+s*tN)F2+qz&6E$8G!jPgAXN5KB3>g^l7Y4QDfXz zQj8Qs*bJ$d0eb;oiTRa0={>yE%i^s601|+JHT;zZvSLVKkq%x51R?@G1%jhgSwwm$ zrtJs))EYK2K#mhY*0@$e(BVn;Kg_O&YkO&jL&XkP7neZ4>J(~n8YzE8exu<%IM1$Z zPu#2SR)hP1e<4*VE~P}Q8IKl_e+oW0KZw$n{53SI<%p}s1<-9=h^m~W_qkygRR;kE8nY>&wh=22NK ztbhd67%ae++J)lOYYS)$Q7fjy()Q1n{L4c~g3zBY`HFqK#Y^;#B!QHCrq0yZVN@($ zlPyTZypyrTu~RRa-V)+%frxJ< z$$k=iaXm}SztUxKppOXIWQ<6`t%q0%`6@%5ZljCt8^8(QRloNc+5+50h`YA>{{V8_ z1+3H}%DU6JE^z(IIWB$zP_q%)$Y2uoWC{eK&mz)ds5zo7;~E~NQ>Dfd1XJaXBGL{) zkZLhj8PtOOJw|GFd>&%`zXPH18DG>_f*|EpEcs4Is(2;XrMJ!gC@h&B>`fHdHeM?z zCuPo+N0xYHcBRW(FlS1lPe3?V_fm+w3S=6Em1>x(8jcy|Q-T+kL?fVOeZp=iQBHV| zr|c?-R^`MH7D-KH3Z~_)7;!R-A6M#K}8 zI~NFNG6#RSIp7sOS1~Xy?$73FMWq?_a2VAsUwo0t-$Hr(gH}ba-%&CnR;c3JY`9R_ zrxoHbq@c^@q$BP=(fEt-P+e~3nyo8KqzPk;CsSY?{YC)WJ62#8E6=~E zV7Nn0@-Cp#@`Wn92TWF;4MYa0_b&>TmnzgCarRILCY2JjN0k%OEySh9Qsz8@pk%{e zj|<3ZA=89gC%J9FqTb@z1HVE=&?DM%RJj;Y1P?5{4`g5hfrXke& z#!n-444nf&c(x2}(QS4Vdj(4IFBfXqN0YXpYEl~^6nbc$V#C&@wJuX7a*&Bc=PuZ& z{c0~z3dYs!p%64E10qG)cb8JWw!o_;Y35VE{7)Jcxo4SIs83|rAt>GR0OLr0VS!q| z1WLvQk_J3cApnGc471Z5+|UlftkzMvJPZKkoS42JC55Jg5RW}O)%usN{{W>!hG9#O zh*N6G09aw!apnUNWeomiI=h$W@x(!%;G&}~fJLA#z~=dreM7xNy_dH+*smlqN|hWv z&620t87e?G-wWD^FRnwU_dE|U%T6l=+^I{)RhUiu*zoIOW_di zpAzjVe4&m&{P*~Z=BNQP+|T4;)}=0MBA+O#W`Af> zO;5=hFY&AHTOZAC-r^LXQTGWo9pB&J=lFlzClAMj()yim@CD&AX9VoG7we2>2oYDY{Z1)N6C)%!~}G&V3(mV=@O z{{Rxk3bBANiS#hWy5ahR5pKVMlvq)rjzmwHvhYJpqOK&6p4l(-F}<>iaiPb=*UDXb zn=Jka-9Ur<>MQklxDgut4qP`zt8HO_-N!~@MwrT-B{$&>ptP*q z&}{UHup{IavX4H1$kIAAF=#8Z=EbsId6l&Uaj4ZD4|9qSx`YG5cwf|8I~L{DD=1z{ zJw!oOs<;$u?p??62zfOy9$2iGD2ZDoTqWkciCl~l_Yh9R4Q1ZXN~7>p5#}W_9kqF~!5;=y zp{y^6Xj1hu6e7K*1ZId<^lKn~QZuc6!O-xCT2la3b2JwJ0LoK59WppNK2ezQaxhRR z+J^SIKtlbt?w&~k#3>tqHk=9q#~D5>>qI&r^D(lH8QKH56TCE zy~@tHT>k)Yoif-24W%DC!!J^UYMqHnbELE-EEJ({zA{<+!TFVod?mOwh3X7?OOk5V z8oa*<0K2jH5WD0Y;})~bJIFVaQk$y(01u-2dWBq5+n#B2a{B>P@F4t#zi|?xyhEla z$h30nVlV7{#~(o4@rH7lv2cR~RWs+8>aOG2s*5OjE(KKkQ?uN>3YkoJiQy8@#}v4$ z>|d14aU{~h(t27g8UKjR|qpJ(Fxec z+*P71^ezs&y6mUa$$k5%&dm@HHaLoZh{>^rplSu6ZWGj?*cP9J8Z`4C!ANJ+1$hrX zp*4%&^(#W$GLE7L1#e@ZexRh*_6}rt!$<%kY8^mwlaLdW-b%w#{+Y`qo*9;#KCJq% z%Nbu&(1uruPjN$4ElXFM2#WcRMfRwvI7(HP4ANR2nCM(Eg8fIm!g(@%6D)q^j{(q1 zm2CAaS|oZMBEkSW>Qy_fGs>#BVnJum?q60OWx&%9n%1YOyo1!O(_*3ob_ti#zyTVd zI;tvzWef>PP+0v8#TyN^g&=0W))844CG~)9ad#mS6h3lV(Met#4eEn-uA%VAzv|Em1**o>mHTj=eK$x@WL8behv%V+RbNhp6(kJ5W8}&y1Q7Sc=7XJV+hwd+r zxGTL#w26_Ssr3`oN+9USS>$@;N^{IhWWVCH$@GumA64V<4!JMsiAT{<|h5dR&7dq8F;R;hLO9OPEsU~&jKJ9FnEPFni^mJxU}28T0-rsKM~d@PWB=Q9X!HTgW6oMhaqo)7pcM~>MDHA z;R+ZJCjcQ{=E@8f43)^YDzQBt{{ReEC_URfB)Mv>5!dn)EoAW?oTJ+1!r&hs zKjsOI;^?`)YJ1PZMNzC;D4~E=8pHtWk51*%R`-p`|>B9g}v`AENl=hXt zv_Vy@FExOAU==E%s`WkQblVY>xPYNS6tD0A6S2gUY%Qzz5$7F;wAgka<~aa6K36<} ze&T|akR??GMG&~i4Kb6Dkz>6hC4&LhP#A(P@=yRp-6eKbr<#G#s8_~7YQ-I@fJ36Vx#R2)A&#A! z%XS?{de?RgyG@mJ9_9N(Pl%EkXKC&q-xnFog152n>Nk7M(6;F;W9@={MOG+sxGc3) z43r(IasfV1%n$8)8_3KY(P{A-(fZyWU7-%K1NRC zR~YjYC4ufan%2Uowz(H>J_zHC zunljS+#;CckUU|k%U=;}3Or7NeZX@9Sr-dH76>alP%&*9MnQ0t@f?ce9hfsOWqeGa zYUs_oO}`wOM_Fp#st5oCQjeI2v>GqecLnR^L5PmQ;d7AlQ?CLSC`;i?Nwkq)s&E!j z;^1dmiqw^cT&Z>9;zf71QI(5}62#sjhTq8jO6S7TIDh~+JR)TFl^_NQC@jK~_7Hb_DjLqpg*qu~hor?& z7R#czD%g--BS(V&01r$WRJd2b0vVxRnB??g5rY;RRj0(Ei+OUq&JO#s=3EFAxLySm zcp;L(shfSDK>XbENqJl&uDmB!9$=lup)IHKj_@Q8K4Z18F2xW30AZXA4@5?Cd7dVP zz-PoxlOyp5;Wa#Yl|mb-UXCq=ADVH=n0@q@s#R}@1@SY@LvgO!M7&NUm4=AO()WI;^TE|@IfKIC#u3U46LJn3Pi6ulg%R(G%8uDtb!oZ zO)*RWzcYvc0EeI4a48!XsrV6U zU1>c=0_}$CTAEmC3bC3(bafio?qMivrNa|Ps4XFvh|yoTQ(91B+z`Ge;E88o64R>J z3Qf>F#(&Lb%S0qs!Gy9K<;|CkmtxsafhQYjSsS8gxOoZaM&KNtL>*IAfSP*O7!0@Q zWyhIy=Kc-3lUx3$mkbJFwi=VI#HMPV2$YvbuD?(dqY*FEuUjM#`JPn)o;-h0=JNE1wir|VAj zcIEL9ZuS+URSn9?2VY9F<^L+4q6J-7-X?>=d0*xRd3{{V2BcPbQU*+73tta~~nG=@~6 zAQeoWBSF=JUWZDQI-;p-*ko(#6fh1)iO61LRSm^SL}4MY04`oJg+ir@U?3^f%qC1x zz$ctsk7JyG5OOb?7-5mmC&Mgzhe>%pIq*vhC&NA%5`qo#7pRDMoX6ojC*iMh4{!#& zC1F_?)TS6bTYWWt2_Z zuOOv)?6?DH*dt{Nz9)#dI$qs<%aA|{Kh#MoXMl)R#Q=g=Wx$+?AA1?-sw?_Ruyt|^ z=dk`}3fwJx!6BTbC+-M<0T}?P$Vc${l|%>|fBM2fekpCHo{$%Qi)YVn4G^P+<+TAS z5Ek5hHblC9YFLw=pl)dqaCD8*-tV~4POh+Fy@48P2vgYDsCO7j?5}u1w)-&)&$u%@ zwMfeqK-3bkGQ<9$g0F=)>N{Jm>e2TSwOCIEEwm>|VK>$N{u5YT9EeY7t%2Bga|gE) zn+=CSV@Y#eV6-j(fu6DtQD`QxS(oZOZz?)xk_+>r!1{>EdN8Y&R;=ux!WIBU->5yM z{M@6(>0AHIX;#JW~>^x)LQrL8!#<{(X7_2H8iXWn3q_{3G_iEgg9hw^t z=5InW^f8=Uokh^gyjSj72pT5ZdX2}1TTm2|h4AwK0C3D#Ar_u~r4doL6-<2ta5SG6 zi~JLm;Jn)L0kp~xfk?8r9xosBMZV0 za2qNu@f5%a^#t|&!zc4XEO4?VQd>->9{oI*DyKJ;5Zj-k>aF&=NRQkxdLZ2J|_v zWr(j>!X?UP;{~o3du-SB#f3Ri!$#n*)LWn=4~b%;UPG22as9X96}nvr^TZkB+fUk~ zae{F>q(YVhU=VsX9lP>FsnF$Y3xSPWP^Z9(@kn|V2NgIJ+-@7intG%QG$87u0GthC z=F6He?-Kt2+^5ZVYa@>*-&_MD)HHE+?Y;GKNm9Y;7wm zZ}7cCC!}u|adxVJ5KjparB(GzPyz#f`xz;^Qp%*}Yzg3iko9wk_ZP0GI~i z`CPw%823;o1f~^BL)o`tLHJ7Z6W!DXok`)Fn{asd89_uoWt*aU2zP>8q5lBaHuAC& zS#wzPj|!+Tx{0f!7)IP{Vlt}spcTl&SDn~6b;v>@P^SK%ZB=9lcmhAlR3CX@m7+ig z23w1@UBj~rLQ@s-nuYXB9EOTQ z78Btt4Nt5pRh61!Bx{OESRd;uGwOS)_lz|hR)`mKBpW;nDc6#o8SJxJ{AuDv)NI_~r)SuCU*)&^B zFi}ikSZPX%GM{-bGzhoWO@f~jbHu)nB`%e*=~RL1xk?7B3BA}5mNrWUt4QU=1PMZT zO8x!^?3Id()6@eUb!s*KrckMLi^f=0DQE|NYF1>@tW#Its2PM-SUr&uHoqTGQZHim zUqsL*6I2SN4un(swH;-j4p_1%Az8rvOq%}yM7y-ST)7cgoQa8<@f?r@MHkh?{1O`% z@d~zo04FXfK%0IFffvl@BPFi#7-eV!9eu=_HD-kJM8lpB)pGvoKu`v7ndKJvxA!av z=CxbMs@xE)JwU;MQu(RpSw&10fr|t0U7Q9M*^N?GU(Lk$nyNNe?s0wli2}Z^JLvX)SrGM0?!}yPC6Y2|r z{7d_ZTSxISKhikmB>`mgr^5nr{{T|5l=R9#Qzw`w#*}&>E2*O=(tRP8sYjx8gjUOx z^h$al2MUL0#D5T2qEPaF54;a4Ph_dW808TzgZhin{6z~9%LRIzFnvoK%l9{irTzZ^ znMHPNq`HDKe8}Xj&d-Q|5PFKLgk52lsD7R=!!9knUdJ?Z%MUK}&pSHAaPQ2F^zKbJ z#JNRX57moWG@AqvE@R9n*h)J4jx;Sz*VJn#prYM58mjcFtJy$YttEI;$=`7@%{|KG zg#J5Z7qbdh@?)lhff@L(cXnJ{S!#y5GTxj&xAyK zt!G)Q!Qp@1z%;kQqJ{Ue^pt()iA`(q--534n=8MBVk+4yX7~}k`)wF)Em@QC)%oVU#c^RBb ze6!{@%ifkZ8fH`n23`$-kFQWN2YKPB)S8^B$Y)C`Hb)7s=Ad{bv7{tv!92cVytL#( zCZOdLj@_}9n4%t#`zi;snL)l&F0%QGuls{U8U^tLG5C)#8GOn(ybB+qCsnx^J;rTU zD~QHb+I9dcHRg1JGzuEnJb^mY&_O!J?C|i<9)@uWtslg%uj*IV^(pK6mGp&02k`_x zCBUB^U8EB#6T%TZxOV(XdVvl=cvt6@E-XKkfGnR_w$7PHxktDkC^q~RUBnlEf(y9z z-R!sGGK#Lm_c*&5ZsrUfL|P}wC{DDZMUsIXqK1GqFgj@r;K%{()*lxDji`Ym8AG%ZnL4a zJ85?>+-b9c^~i|^_=HY&dw}IY2CP03jWn5#r9WRbDQbDb5vM9G&`UluYxgX0XfDrj zDFWUYxhfrs{Xoj6j$bt{A{Qe!K;QSXWVBA&XKh)2o=m(i~#fsfeAx0wJhp)E)l@Jdpvv#-?Y`<13yjY=I1A|R#OeMWbos)4p1qCnw* zQlpJlk^Y*uE-9%>v)m+(zulGz6uWb%EWa1naO!G9Du!BNVeT6Nv0vQNrAOlOXQ69V z@o^ZeSZc0n2MD6pVwHItIvozJr9^SS{tO0SGj*|Rv5W^k5c~QO)+Wr7Nw-}ov_H` zvAl{x81LMy7YISbw3rJUv4&>7QAx69!ETT#30cOmdd9D~>hce;m#_h<$hU46Vl=^} zR!_NqqXIx99-d=BA-x|Sv7ZgZAFe%zvjOSDlSE+^t$% zeSn}g+^nIZFYNwcEq(q_%EBrxnrub_F7I4}Ccsg~Mlj@b_aZ*2hpFZ*Mc{Jl%u7qP z)@x&0xsuut>pR7;)42A??Yi3b)A7tFPGGeTt9x^oYiEjs5x2MwAx$pHxS4>Ph%PFK zh-sm>L(DT>^^_EU#2S{(^p(E=nU@Y|(76Q}xsE_6&S)bI)se>odeI=~4cI5iUE>EPTQorGH<;$1& z=`LJTa{mAc5p|Ck;^oWya+E4t+*nsH@$&pRVC1K87$j5Ud;$u^MfJ_uc^)O3kDkTn6}DM2vHG|b>e`=BO)7%2 zfP;quQ8J1~R2XcRLkN7aKWI~6T<=9RVaZ?H)7_6vQCBlz2=za3EsoAGj>Hr4=970lC&qXRJg0KF8lEaC~ts7MXv&clqaH| zAcp}!C~7k)>7&yu;O|u-5RJ6tu+&Gj71)fF3dZ}DP9P;@L#EaL|bIPqF>@tufs-rRX5zvbBNd~<$bcnOBE~ahfSTveDfma zfdS_|*@0^=O|f^fv==KiQ__Mh=2)g0OQ0DxZQ*$##YfZR}s8gEiPL`gNg7k_mlzE?O!^h}1Mc^@43rZQ@+FbZr9LNRkY{YNg^# z-G4KG1K}wFjeuKG@dgz^a(^+(VOys#{H!&|01)=c)+Hjp5l)Th|{^0xBnq z5Uizl0y40W=%$1B__hgK7yD&E6i185(iFN%jB~X@MCw8FA|e@Zx^Jrx3rqHD;29w6 zLFtKv0|97>?F4E{?-Vdv3Y5$8c>SRz2Eiv3Q8I`O%FEnrb?W@Wr&g#wA&R+W(e-l2 zDpkYI;ILQ9&K0D*OW>uV!EWF27!lf5^$q~mqFQt6FqBc>)jZf0sy{LR00pGv8l*+& zx{Vvo^nF6?R9~{?9Bs8M_XPD?05NtJq2mUZ3OiJ-yh)W7mvDvS?xy9BNH^~8u;t;^ z4CL{k{$c@Xfa^G}oM*Kz)OaNv`HDcaji4J==TU`L;F$9szU6k)y5ns@zbq99=ZG5X z;FN<~(5TcbR7&J5*lvi08BcIs5M4_9mG?Dvec?w)4jYEQioC{FPl1a(M(~#PE$Vc< zi1!}F2o~SRh_xy1bcpGx@)35=B2(YvLR6ZS02?VXeUWY00k$Fh0=6h`Co-kZqOC$5 z$k?*t4lV%EKN1%r2-hb;A{yj)T)iRrOK8E!;1KfStzV)psZ}{CnL@r(IMuH>o!@9c z7mPkdaF+e~`%7Y>r`^*8c$cEaXcTeW7Vn z4i_IQfpz*%cH0lyXw!Xtz>F3T5w($N0$Mh@#Zb9kABY9=q$gYeDal|x+a2)*jaVaj ze~W}af{ylOJ%R#Pn0%X(vU=H~6IuTN5yRtT5sw_L59TJRvOLeYY4ssgd`BIfp2CNC z>n+Gc&4h4?RWwz)ilvB(x2U<1P2h}3Gz?y{df0DWs9*W3AH)iS2!N@Mk|d9m%p}o-9gayV(ZnmP< zHBv(D4z5V9zHTHH_3+l7<|-0eDNQPciizn*_c zcm6j|_+CHqynn&|*ZdBjg1VbFT3T9KD_8LI@n)k%esli-0&dmRZv6iMJ&~%t{(J~~ zM6{ji)ZAhIM$eW}&~&PIVjoeG!1kh}dnnKiQB{aiQ!y(KHwW)NI|tBfZw0+iqlE=El;Vp9PY zt0iLb8^bn!mw1ZArg2Q0j}pCW#5H-&2euvAxMF6&^Wr1ABzSs($e+w|Gir@L1?LGB zV=?TkxvkCr0J%>V0b2`;TFB|Tio)hfNF2W^E=%avNaEMCN9lt|RT*C9`0X!JvTL*A z;lEYtL*;=ROQ{RD_aE~RPoj*@&wj_6BNws-RLJn72EO7QB}BI#;dY4%)=i0ebLlT9 zGL%*3ULe&RCrHBR@hU{pZ}>$20C%n5H9E7vu=|Mh5|9tj!nE;p5;Z3;9Tg{PD`Mc25R z+O5hLsoFcp*FGVE;rs_g*CpbzFxTKqtTp!hUM;_#l7&jg7I^;v&gmTF`r(VI^+FYQ z0e=#_PX7Rf47|VP=i`hqxp|JlXv5f`ytveslt)IR*8Tn^c$NbW>0sP8C6Dk+M&Rzw z)L@+8yiS`^jmoE7Yam1{gB29Nt%ZPFOLBV12zY^Sh*+}cc^qr_Mo26iOOoRB6jZYP}3!ZZ%WBQDVx>Wl{L_tn0N-U6M3;N}iCK>Y@Pr5smEX9u4lisxsubtB zmQzNh$&GV64{+BgeajC9?=XYzAZ%p8tA{HJqk|5qEpi_IR1Vw`e0Ab&F``)tx*=Z3_#{CUBG< z2wSVs@LT0ijY$m72lDb(*$o=v76A!yk!WDw%sC9WfpQ&PDb_xVQC%_ z3cYpwL$GH1lC_qGsU9iv23?hjdBsz49hD+v?mMHb;DsseE$|=Ziq`B{)b6FeB8ER- z62f{MYT;Z3DGF-ncvOEUW$YFHbJ;-vjpHf-U7H11p*vd)CU8e*A^RZtg0JRPpL?j# z6jqIw$k?dAXJO832gJfUaxITas1N-REv<21#p|e)F{sC>sxbTpD|ZW%N(Jw%M-cZb zHnCn^ZAXSJz841&Xz%wAnA?#Y`8(@SoQF97B_b{1*sza+S>c&7>)9TtsjG0Kw}#f8o>dl`_8^ zv&-_YI+u&a*J0VzIsX6*E|>#XICX{B>LSN!;JJNX zN}m#r`P{vaxP&tzbj$^Llz3%dnY#mJz=}j{*W1`?Q0srFKO6bMIOqrum}4$UrVILF z_u^UMseWEc8!7Y`krqO=w_@h71IRZ8@W@3WQim!aaPWLf3S0DyD)ZbKGHcCngJmFZ z8aT0U#PC)h%oP|58n@qw_AA@L!v6pq2x5H3zRoNqaw?wX$jwwE^o*OHX?w<~mVZEe zKueiAzZ209wjYnEYj#lB`i=1yFdo0D>UmKfl^Cv8Z#~9IPn{PS@`i6V>i+<7#gH#u zfM(_mlg-ULFmw^Xd|WdNwYe5^uJ6)Yk1Pe-Ips&e?SY?Qz7momwt0ldww;Wj*cyfj zRNV7Cwjd$Wz~cCV#ENgo_p@-nAXSyty9S`t*SL6W3k0c4>2azVNw3@_ZI0}ttXCtM zuX_58Hgx)z8bOo>tNFj?3vQr3AN!6Z4mm4b!|6LN2Hwlp{eN)*SZ(7r#n`#noQUV@ zClVY7fpJFZfS|yImk@DkbQV(VD(q(V1Xa(PHPqqwP!2$8Y=OUsJTKJB;JJTu=4Z^$ znV&O0W_--F>{aXeK`D!EpEE5B$imLgl|1Asu2xoBl?7(XndXmC$70`Q%(-r*ej!TY z41eXq|-LfptDQPJ}hEYv~CZ0weY=HWd|7DXc^ zN1B2X!rUOGQql3^3oYngpn?)V3{$XZ>-P$Ab!{B{RnEc2>}D%!zqxQ8gb#=T#a2Vq zxzS?n=Vn)Hrc@6aR+VkXWi3b29-=;zH;<{MD;j=?Ex}T$eqs)ER;k>M#}xv(i{?b@ zDTgov@%I@snn$XodzJ!`z>vCw%s_5Whul*2kMJ%s!vHiN5JDOk3+MexO3A=_64ijg z1p!?M3;GP(j`TW&s~`pNN#Bx^<;TGpLUJ1KV73fBHo$zt=6IgQSS?n;^%~dUYK;282yte4-0srNV{KaaM`yNYg}{{VL{tPHUBi zR^aQvb}>Y^@G7NcWo2b!tNE-Q8Bjwj9kv_tm4`O7CHqVEn)QGWWg$pF+*Q+4%uDu$ z#ls6g;#NIVl?L}GBw&oFoEZYQoGpR%E!74u$9Ov zz&UbRZ zpK3HHjD^L+LQpX4-5{LdP`tK2acMIC7zY70oC!kuGQjw_(XFCsU#O7Yz^nHBSg#NEn)WRR zVZi<%!WLSaJjlV*>N#-j>$5Xm2Wj&w)$niP88S$`5kyZ+9;IqGolY<2;AYG;Uerj{ ze<}X}_9GaQyXgbD&^J}ziivz>TlJX47Cgm@V`}U{Kc)**5lXc2JWZkR_W@JQR+0Pa z`ES4C2$HYI5k-aHhhYZ074$&z2FoaUokfr<2foV_!U|RGI?Ma`ddiwySL#^wrEUC0 zTZUX5l|o5NVu_I9h-LeHL|9Q;Aiyxtyf9}6w(1UleMDNn;u|0v;Tpib1r|X|LIcI7 z0#Z1Ht$t^c%}&XdLfA5l_4tQj$;1BuH03SNKGW?J%4^T%!|~JeYDE6zpnGZ&jJU1*Kn3OO9}{C`Hx->tDX3}_r0igM zi7KVd-ox1qlurTAa?I+!K@vC2L3dLj6KHIH$=rQ4@V48)|k8tON)B;AMYi z6T=p!t|cHG7i3r3srmLeRYh#^EvC&Y?sqX?-38I8JWrT31+#_W8L;rv(E)>4pC$hQ zsYKDFzllPZfy{Vxz6db-=Fw*~$wT*Oq5{T>#RY9oK2eCM)DoaH%4gd-L#3{sC9Ve8 zNHpizOM6YJ$Ol7=cYhquURRVZT;c(Rzrr!g6b4og7S%c8qrezQ&+oFivDa^#xIkC7 z)qT_h5n*gT;&p2d`CP=9(ROxI3ae2R-ry+xOfTYI+fg`=scO}W2QhYw6}}P}n0ggO zdHR7F(y8$r0FKpRCJnGr&O$nkfFI0%oBjk?6Hwi{bPrdT9#`Ft5+3#%LyFT&)W_H8BkXZV3#u> zD(h42_)Sc>+pI5P^BgZpN1zP!5+Z0}O-miE-o1}f>UdurfF|Ep3c#ux<~7SNT2?6$=}@L01ZiABvb|JquIs58K|1yz%mSvyRCTKO3=@4vP!CY5zO zLK5sK33-dqEV!qbW~hhXNF@{nTb#OlCnFMNWFtn(s-F?>P;COk2@_M|{$P)xw=2i{ zltwzf!sSJy;v?UCY@|A)7}IK&g&ewcSpMeqNM%$4%eV}*arc{n1XB>ZQCnRI@<1vt z^AD78E{4$yh81`j(6Y-7V{>w(_7?vD)IK3-FJ+d#FR;L~q2F*~Y*JZ={nTC3S2mlk z+_}r`ypXhx+WLQqC$YVIysl!){rqxVoQT%F#ZMY=>tA z##F8MKC|mSv+F*y>prvV9e)dcC#P|-QEF$>R`Pn&>pSFqQ|lGB8|E429nBG}j1AoS z#g6;+DHgU;HdMQgxp63}$kaD^bM}HAJ;Z+p;1aJRu$Z>I%19&TS19>|LZZFk##`bV z(Or#w^o*$GMLn87DOQ^}=@TdSV}^9pBQbwO(wG;8=_!z2EEJ$lV7ypl1<5Q(MHI_| za^>Qtfkow*WnM<(=ULNX&)6-rmk39BhhibDBicA&8j(~c74sER6^0Y5E7j7me7I2o z2Xd~t*hk*s0D=bDvVks z9S}9?q_*#Z1$U4vPmJWiQ7#0M%LUx4xd0NDbF8y%D>%ZdRShSX;} z5|eyOfgFm^0KxEF}PwH^K<)0@p6L>RT*mI-!>1wj13xZ}e-5NXTH3pW+w^W5f( zRia>KW2W4MFdwd%f8$n5iM zI&fv6j<>q*_8H9=rgYT!c`^`oQHf0D;r3&A9Ar#Sx&A~ z0SdAZcw+1MQAW=RiuXES zSj#=cUuB-ih_zrj#p@+0R(Xzq%a+#D)Ej-NY@v534O)d%1CL=; z0;u%`a#wBq%xBWQmn~)xJj$dnH$)L?j~01}ny!pcyNczbO6yq#b0Q$d&~^Z`L(YDp z9|DuN6&pbwk-X{TtJB5gdqUCVW(a?oZEK3V93a)daq=Z;c#~>d$GB{&e8OfA6WAT; z=GQ!>#^`0kho6|F*s_kFtj~CGmzbvtiwD>MIagPa>3t8Hh#I7}v3S z3$GMQ{CQOV(czd-309)mp(*l~Wk|0h!kRFtOc}c;a#uifsX&*(FtF;l#q|MIc|(>o zY39Wg0^QK*2jNEk;#!M}&3J|g_{pAUKZ}-Mmt18e2fS#~ldqEqxOx(ZABet%@i4P= z@s(&DWbAkvAF&y-7S@l zrp7kAmZsSZwhP{(v^nN2XA| z4-s(da(Nvs`GB3)O)uPU8B=F}_5=-^*=e2Ag)qdeRQ!0DK8ik~Bmu>^sa#c6`2PUq z`%7}k^QzpbOtX>|>^;vwsq?8Vj$fK^M?e>G3Ui zpV7DGTfGrWN0_0EA}Zr=RR^DcaF{ODPpGx6V+Y7ZUt4eBfy$HTJ`oO&94ELmfOtK@ zOoc=L0G?nbhF!l%7rV6L`9tnjAC7V&yTHavd&eQ{sAz=Ls7$saNV4bPu?j4CI-V1U z;Zbqj_|IItRa3OPQ!Mi={{X~6QAK_fGVyfF+X>-_43~mxh;;K7xfzs3HZCsMu-SDz zvH6JIc3#}Ps8P(!CFR5gmYkPd*CQ0qGs$R|q!n#{aYzP# zTZuVw7=ePNCO&a6KYuYf(`9T4!}a;m}`U$h$60hje+NlY!}TEd~I!FXCPq0O?wk6Vn#24%evj4np+RLNN z*z-TA)+@c*e8AV(ceW4?+{XBV#{ha@&~vpT+=(lRS%k0vy2-)K`@>9;sR^?>I}8P` z`<4stM%isI@IC2P{?hnnCD6)v;m~|`R*Ic+1OaiE4zC|lsTICK?f_9$FYa8P3&-DP z#9cr>kYPzk+fl}t?3>$fmPw%9RiMK1M# z5}R)sG86&isb|<&8EMKK(uZyd9QIrd4Im7&gQOIzW%z{9^gC1BFMDiDn8s)z6%W*M zm~&5}P)wqh{UNquEk~F~GUB=>Gr~Xh+6UhdE(wK0=-|f5N=!b7!)}HcuNVg z<3soWWExlCt8!#)8fiXa0+g8XJ`^8}blelE=OAgb<|oWgn4d8|VtmB;iSrTb6gtXI z#9v}9u2hQqE4JQ7d7UzCQ}<5gP3C0CarR zyA?lxQiE!1))9tBCg;pUp+l;(v5%H%fHI9dMuwBqk#cE60-&{BN{-VXaOY*m>TEGN z6wZVEn6hoB$+DADuvdzjDi`8=j9LovP{4w{mnpM*c9MDrR&cz744D`%V z988FuP3*+@i$eN+!SoE#7w%fTb!B=*dM>3LVYe=lTh{*KTva`r{{ZqZ=A#fQQ-#4w zG(+b02=ugAg6NBT1K3I&f>?VSmF^gY-dPzDuw!?rJt5)nm=Il9oO=byTD%XBz!dL3 ztpJm1af9MgLjM3W9+jzYkQ%cq zmY$mss59FK+TOyc+HF@O>PN>gKTuUyYvjKF05D(x6qk{Vq<9zRS^)uiY**A_z$LOQ z{=d13G|Ybl)|@5U3BOUEe??$B4X31IMQHl(`ixq@L{V@SK4qdSQ`1%cC1@yGmW9oa zl%%t>?f5V1Gw&6*%;bk*&&LnR=kjn)AH;G00P^vV81{6Weo}CqC31b|FXB2!lbrAM zJm4FwY^NR{j^By}l9IWd{-+=D(u3_%fMv>N+>Hwhid-UI^`xeosS3uyN{;Vs0@kky zUnq)xpd7iMc^AY4cznl!OZz79TUYfiG;^^^RppdY@hHwzk9PGaFfH=e0xa5qCjcMj z41TN;qSzH}5%x=Sx9q>19dcJB$BHQ3_4Z&>?8XKJv2ykG2sD78iZm&=cF9zHjD01~ z6=kdJ{lMVMXQ%@xuXV9srYfBTFt!k{OZbO5qu%_)ZXxwX4{e{59h zn>&ATObDWC3AQ}c^N1K;yEqS>y- zEmp-|k$jG-#(Wa2o{=`Qp|e?{SWc`5Q4VBqEG0fk^GrL*Yriw*o4|Jv3X|dOKCFBZ+2nM?q)&mBip=@Q9vNch+ z<~+zmF=7_Vz;%R-uHWVnV5!zFcr(&&u0;oD+ACUYXl#v=lzk<6((W3CTUksb?xLE= z`?29r5jgA!`hxvTV#gbBtR?{^1l(3n@XPYhdOCf|nH=Zg^(-M`Xsj^gZY0(7Jc1_P zbbpzB##aIWvcF7e z8lGkX;;^`d0HWGrD_hX^rLa-!7~8-6 zXqEL3cyhd&$JvZHdqVG3jZ2w@s6|B?%9Y78*2jw&G_Nw0S7iE@M;%#X zQYr?-xJW7x`$G?)LJimb$_K}A9>X@PH+L4Wh*||7;$7em#7(~|2FY&?Ld6-?oYTJl z01Ru}Q{Lr-F1p^W{jm=QAB&4U$=B&Gc4RWw%mVa=K79QCDE|QcTvH7jGZRjGRV!eX zFl+*wpx1jJGyJoxr6L-}nR`n6gQ5G1RVv$}BORs8kX^Mky8!uvh_HH`KBAiTEw@#U&zMlYT=j}SsbI@+i%%w+!D}bdI!kn_U9)3jYmxZ| z#Q_ma@0gBmc7x0LVZ$bYxa4`-O7Od+-Bo)XX2`{ivA{cO>W?e?o+z&X9)Gwg?|;XL z-Yr=8>}jh&eZqN%e^aNv9gmN|PuRyIc+UR-bM6x&c5=hB&K&;$fx$R`{&78L2jhZ0 zP9N}|W7cvr-#p=74H{yFF=1JdV&d18i3Qq87%4* zIc)x-z%riz!g)f+x|gsi40!(l5a{iPU5>fvqNOg`tBtJ&7XG|g4XZ1<}wS#Fze?rpbI)&eW)2#GA)MuN>M z>@VE07SB-)U)2LRJ|GUgOEnkafa;Rzu~P&*ejr+k+IwIOuL9~m3XO=Y`BubLt3WNcot{k7R!Wm@XHkz1h%b#Iu$x=X8(gUI(b_6gvR zjb`WUYuqm}9V$}S6g%V88fPI@{l*2~UT5kn^szXIQsRtL?tJkxp4S{&wj%J@Rt5w& zRsR675GYzYrTT^*B~^|gAi;O$UkZ;z0lTt>tgh5or22|BtnGs0kyUEJp%R^9o~sf? zzS(cKCzNYe&KNb!iPL|ZPcq+Zx7#iD%YCxnZ{vbIVlJ#mV-lLneX+clo^dO&E!HZI z!#JdBb%|!NUf9-a4KswdwmbPCF>QLdl-4!1h%({XfP_2|TkLp^LfW`NrZp;dlKsj+ z3v`OTZZ}q;F)8dykdMKpUj$gCv2ZE_nEs;*MN*G3Z%wYTKtXgK$J{JVlS}@tU8L*^ zzql&@!j$$7dlKBwT-1Q5diJe zFLX3E-vq?jfoH;KIlW$t@sVY|=lY88JA7hQz859D-PoTj48OyXpQRpPD#QlVv@Y{Y zsL%=(-8UJycTTH(d_~^yWt@MQb@L5E-oSgvHR9pH_yujX>L;*hO_6&>-Lkf$plX4= z^8kotM|t8dPNF*Y<mm`o7hWVsAaIrZQLVNOC@6Dhpd44cMTf6j@7!xNr@o(PV& z>FOFEP4X6zT4*=ST5uJ&L) z(C@@V2!Xe_Ymko;qr~a>^4zgiKCxSWiFm=Ve*@`0lj#e!{{SDXqOv)1J(a4btv;~4 zAo#)c2H6C2v(}bSS2-&9l^(%7xB|;%JfH@SK^pBY3UIz)DOA3~AM})(xT!`hF<4@? zSXN_e;*mlQlf9W}sieYk4TL?9@}qC2;nrQ6)CL$dO7@ z(SGNC$OMy zh>z1GJlvtY(5NtcBE%i9s7wXb@HH&h-we3>TWzF8{-eF>D*S)N6S9ko-!K3i z2jQaI;xjxw%M$5f{6!ZnVxwe5RU#q-TNDMwQY9N*F{R-pM2hG;9!xu#fH1 z_6}tLKIQBJ$XKKb9b>g?kKC;}ma?uTAvv6ZqZ(ghusoN1A?1H^l2d2QYX-qX)Tv_2 zv~XY6b^H7P+1KJ)mmDoioRj@w*s=Bh03H(M%a5!Wo>6F6 zm&ujNgo_rQ)UAKFxapJPDq6w}tn?FSB{fQw`Hr8(xAigiCqKEycuK1CDy2OdJT@m@ zg|Ma(ae~bB!{@S)nsiMtqN(tJf)a^0;TuT0ygkYl2WPy6{W2dDLMV*F{t$5j2f0ZD zc73Axl*sCZ(g)unD&t3II6h`rfHClJma3Yk^MoF{g<5!nNi-uzVRM$pnz)$*i3T+5 z4K(8n4GQKj^jCJTFU)jGp|^(R#OBvPYEG{{gK}_QO}8C5_J%8_v&?me1&<7 z2SQ0l%OBV^uotqZuYvRU{{ZOwehrJ#KrII@WcoD^22jt!{xM|rD+5c6LW?RNgu7eU zXOr=G#{nxRSUx6@Tzo&o51SbWVW4~yub~rCqwbvmEB(w*{$N4;`1mp4N{{Zsj zk0%qa=hN~Qr}(E+{1eI@C4LJp@Dd(A;lTd@66x&Wy9e=K@lK)ETz+L%zY@VZe-~-_ z{1_2yj8zr_-VY|?L$305TFWQG;!vvlP#Q*@sY#j(Jh>avr29^s8vR0>H7t=fx{DH< zZ@!su!^Nv?E&Gp{Vh4#p{{W=LAT6&CBZ7dBDlU1h-P*mCe*_Fkbu7_T`%f5&2PM64 zE#yM1)Hq#13kSVL_NPhsZ2JHX%E%L`muTr z6RA-zQ-Aj_0`#Yec*}k}@%U2@{Zi_v+$UfQB8F^t+%E_X;k08h4F;55N9+(Sv$0K8 z;Zf{S!8a@^z8{ItJZC+Ba@^wlLa~eS9oxJ=QAA3nLt9ipQubUGe8`0tlP&{(NS1U8 z>oCc)os5jboT|8Wdnle8;sdTXPq}96Qpw_Qs({^3#aI6Ta}-&-Vu6HaQrEP4Sc~hD z(P+Q`XN_O|$E}v5usRWH_=kfBvViwYhS)s#z}?hkuXkYO?k_$s=2b((KDf5(hkykk z<@XYV4qxM_b$msjBHSzLeJGFNT_A7VHNGcL#b+aizZ|CozN4ZD2 zN4ZD1(UrcUaudzS>s^esUyhMl=ff7}i1)~~Q639sPplJN@O;35&13ZpwiPM16RxpU zMMrc1be%#CBOCZeDiK+8ea9;=;yp49Tz(!$uQf*^T}Q|iLOUJf9Z^j%mtYfDeU`GP zT$Ip2mu|pgwL{3vzJV*!2(7Rr##ce+0$Z5fKB1&6u<`dcxYxBXccDH9?mMBVZjFV& zK2yjO^pM`eP(Szx`9=) z+9I#Q^93MZCGxs%1w)3%<|6?1c_0{F8PuAx6!Y10Br$b{X6l+bio(0lv*v4^Xz_-H2=(hX*f^E-J_t z>^G95czA^;ol1LwZSw-#7$~>`J20Ar`vz`ezGg(D8+KNRuQJ~SnERUm2keb{fkYc< z1_9o@UaAO97zFP@2Bg$GvA9`5{{T^M$DUkwA#^1((LP~RM&(+7?-8?x zH>zn5bt$br<%cbP5{n%W>GKFsiGPTz4t5x{N7D~8NnA2Kd7Gc4O1L}PQabIyZ%^$p zuJswu>Q}%E$zQqa{7?)COH2V&s{6>UHLMrK^YLO896CH2D#8TLtVBSiw&-qb&3L zj+#K**1=eU?Z#*Z_#)x0&=%1bQ*e-WL(GLM13 zsFh)&`-ERbi0l>BXHq8ie8o)+%`p$&wGG5ut*`Kcr38nheuU@H@=fUB{$aC8t}Dw5 zjb}J!!}y4rq;Nknz}rjvxN77YM}kGHs5ylWE(`mc_21$W2EXQGX7N4$iiiq~6zG zPg03at)X z&7qW$bPA)2mHd2Wvd(0sZX-8Q*dU;W+RrH%j=iXWXZI#wz^_pOO!dcS@$nE@vIw7t zp!|coKbFR5iBYmpm!H7MR+ET>S1us9#uus9bp}6y6@(9C@CdrV@@iA%(k@W^E^<`~ zcz2NL)E53DAon^?h~W?ZnEYnslYPN-T=xQp&Jh}>E+Xr~Q`?3;1>6=$2w}Ns->~H# zzfnbzy2Db79Eh$#0nIJyBUWYFy0$JSl>@>0h(KHp?z3f@w2o|Z6nmTVDFu*%5fo#w zXuG*WfKqSr>?VXzbzgBLwc-g%YfKch`;Pn#4?oNU{;_-|kc16$tQAkX0N055_H_;`oO0e2d~`u5%eGcydHXtTt!s9&hrRq$34s)n_$+zSs7Hcl`Ne9FrrUHFX; zFCaRWOws6+=xxKtX-olp1R|$8Vj7foCm9wIz>1yTGyIHmy2quAC}NIl8k*%#UM0!O z3@2cMB!{sZ69K$tvHr zF4`MAN00Xlb)y3u_TzNte&UtxQ4^AiK?HZQ-gZAU3?LkU!_+{eRL?O5;7^`kM^@rkSKXBK>Y_R;v&>+30Xj}2PS+=?L_HsM2T0>}F`*E-Z)R~@ z`2)D?t!qj)Gx{8`SVCKf+CF1{A6*n84zSL)Qv#Zed58J79fu*Ecs2^li^4g&$ci1Z z3RtfZsyD~X6C6aub>ss;`$TI_i>vsHimua-afAnl#8EXC{3DZY@7z2}y#(pZ4iumQ@sZaLYJ*ME*@_DTKY@!vmWv+bpS zRJ9}Lfq<<&x{ACsP1dpsb%cL=I~N28@hz>wc|+%E935byGApCzCF?_95EH7G6ej#c ztc&L&jlT!P@%sE;#s2_R&$CI)JE&0p;q__N$3{H+>CcxVM_w{z=E{{sJM8em{xgr1+sFFeL*cLqBN@p^7YQhF}B_c>e&Hd;qvHd;)IZ zXL-Ki%mwUq##5Is!+zznP+akC{-VaIpnrQRJ&It) z)&-~TB?2*PlSS0N=I%3CkrI#Y(EX<(Ek;8ECR>q4tjR^k$@fF)m>>P#QfVf4@ z3+8q65YqUS<>UVV-To|vS`M{l|-*+Dn3W1N=o%OF0QOABo2D zTUCb!QKqm6J-qcJ>KDUpeh~hz_ZGEqpEG|4AVQOG`H7dzMD$#^{C!Q7EEatGjoN=a zBYNv_GsfkvtGt28v#cnbKf(+iA$UWL+<3qUrA{G|@S&7)$q9!uci@IfBd$sZr3b_{ zqb0h4QnoitpDd_rV5!;RJVjfuB-qtHV|v(zDp0!FPgA5wsh>1C`M0@ma^B^=$6^gj zdx>tvRey>YYAmgZ+m`nSqS!*w4YDLf&z8pVk?GjB??}+yL8-WJ^6W9G$hQDoDdJg; zm*y5mFA!Bb?gF*swB)>t9}o@;;w^W?S027%2@>6}#N`d?8e>CO%mSABMN!j`64V6n zo@Fj*e9G>}ZUo5VIfEXz#Pdi75mRxhzf!qeOWKDZA2=dt1%D)whlCr_;~%EI3y-=e z{zDrBjhKERY2S;{*=U)yZGI;9KV1QI!rahxUogs=8Vx%tP3#?kRn}V%q3?x{MmmX+ zgst}VD)H6ymIltIo}ycNG}o`(ZD8-XV5L*UKpiF=8oo{qpUk9z4nL{iGgklaD{DalaZ&;jpHvQ*0I)it#d7YB-hD(m$|)LE_)r5m-NzVn(V33#fHV(#8c66bcf9 z!f3e&fuQpM3O(l^#OgOdi&<7*)>Ko&fZK@>M=~kmB?^2i#8(mcMTnKSm)HbDaZT}s zT3k}xy^OIT^(cm?8805u)A+0p`8a-Fv&-{@FxVbo`!eBq9itc;HwuwL#f$ekoUqj! z84pNewPq{Nu*Dsjfhmr&~6$g!{WB&k}jy>l~CBs2y!UovbzY?|{ z6vsVW3(Ajnjoe+1NtLVZnKLWvY%!dAg7bS33E`y^PD-X8To?@&+~2r+z`Wbfs6Jk_ zv|u*(^~{x=bh+~zfo*n2x`O<&QNon-_%i0_oD4s8SZrri0iQ`&jD(SXWBZH!vd5oC z#BsLr9}En5K*kFtJX?SIrQ=17HtG?Af&r_Im>KG*b|&azIk5cz0K(u0dkdrnAn56P z8nW0GlqxJfrdO3TAVBIA(A3~x!fYJ;Y9QfsExG0J40HbB;J3FS*ybJJEI#4z`j=bC z10ZO9p&b^(N^B99QSs_mlI)Pl6l)X1?1n0elpDCT2(MEmqleTYR#>(*)HshDa&b=K<&e*oMm~;%M+bT_7dWglAUg>MKM9E+|+;ps-wu2=$&T+^plB_pGLm z3;AM#-V?`Z6dw@2ABRWdxp?f%!IP8fecB(y-qb~{X*@{IunP#Us&)H=VTK>XFpVFZ zi!-0#>;4{piI>zx0`cqS!F2|u(qc8IR3&paoc(an6$K&m!-os0dPnOe3dnb&{I=G>N+yw%uZ}; z5V^_tR{I;fE%z>5xp6d?E-P%kMAA3Pc}x?{`GVND5r#(lfkL9JV{Ngt?9^JiVzxKR zHPbDMlw=1y3ye$m#7ENnKvyQ1=}t!$RSN}%BjO-VFQ_&O-jNL@`)4|KUV7Ia#%5aN z)wc44Fd2ZO#AFF}C`*_`7Mx+LEACg|IH=+lsS0Hd=_XHIm+k`+4QX9R81TfW z1z|*}WIa!e&)~Ke*&|mCZwr%LWxhgdhazMG>pxW=2FL)emOjs7tA}?$!Etm{QeL9X zDQUIrMFBy5au+aH#TSGljykNG(ED4vSNV;1R5EW#c|k+vyZeIFAO#8)E$x|s5JL&i z)V6wVOpz{e?W^WJ{-XMh-~wEFsjGq}G2~?%F!-KnMU8Z8#>%I^MqX^8>{@(m*9meK z0D~VWOb`|KE*xkE#=XT*idr-5i*y&kfc0@5buSJ#vm0u1q4U810C0cX6)Uk;GSq7O zE66iq^oQ37mz6;DWC1Z>;%O}bPeaUhjn1XQo@Lsaj=l00ikRtf-v0m`X9wX*$$WCQ zS@-z!{{WW{%hp^>+4yTR?61Y4e@S|TE8;R+^&b$gHv)re;v3qsU3q-K3sYWCT43^5 z%&b$-V{VpIEDrk!Td7fhsY9oTqy>+ePva7Z=A)N?FgAY}Yek-Cdpsj~mlI*5?H?qD z!o{nKD+0LhuzM+z*iQ0qN`&UWi4|8DPS}b zUmAFa`~yOPup8AJo!P>)9>{=LPcVN`UekI88b~y;QGa9%X$n@{OGb6~19O++TGiQj z6RRm;#g|qe66NWhjY}*i=fc0Z3|~w(EVAr@Xg*}wBScQ&vGqaI7D!qmoWwWV$v+R^9b0>de6AA8k+F;9(Xrw0rWo$ zs^2k-#=CV}KHzK>&x8U~`$x)jc>Vs-yf+=tM*jd47DS-0No;5e!i$`1gW66rs)0TW zukk!|F!{JHi1ASAHN3*=Bkmw?8!J5k-yvyioIO9OWrCd7a^f&Yhr|VbGPgzS3Lbq& zy@X(l4$J&?*gT;Izt$!zMJXQ=-WO|0&I;eOSiscwg_Y;{P#L46U{saGN+ggm=&4Kt zt6balaj%th1ngxf0rEg9udb>K46I3M&cYZF02nKyRT0xsD&bz{D@PlL|xd2GZ*w4gY)>elJaPEoHJx9Znm|xU&M<2w|Yrl-yc|6PdFVqJN zWIlVG6+{8I;u3U%;|WOIk3=krgw^v=f+>>;u{ZZ6CMlGaO@rBa4b0*kW>gOS%hRgK;Z3x$q1x zT(0!VeQG|5v7+F|Cf(Zi9<;f+oQL7B@%cylC2YI&k6GFO01JfTJ^a1@0FB@A!}H7P zJ^D^ljPjZvQTXh&UzdaNI_{Mj-QdAyY?R%va$p z_RD^6WsS!P_B@Irl3(tA;X|{CngH7RV1uQ7CzL_9##Zc$`i(-s{{Rtc_)GHnIYR#c zQH#_0Lm}JkF@I6v2(5@O(H4PwOP?)#BVxbN;79#Ugt0$Sd(~qMaeNWXMw8mN3kauJ zq^Yc|d<*Mei>vEq8`1z9hJE-^$h6O%_YRu8Z<^$-G~ z&@I#z234ZmcP%#`36Upj&zo*2Ez305hEYyobU*eL0)YloP(~sbKPucirH?_vaCDPlcQhURlv#-)EYg5ebUizyx6;sWcs7c!Ad6y z#CsTI`oH3$h@`K_56iPECq7~;W34gsGxToYCzcOV*?OZ|Yb07ytn_kBIlFdk=0(s_MkmcBOQ!`6J5? zIWj5zrT|dZ`j0^3-(@mrUL|z4{lbxW8$@7u;D*5nCP0qfsvrot&o%Gx0U>I3 zIt>ubp5W5-d02}Au)r=A-UpNSa+8HT0=2j{iwxRUEj`O;A7j)4JYJldycG_18EX^5 zzcS}L3g7_Q=HL&Ty-!SJY`_TgAa%Y6E%o@Nh4PI$#zEu8Y4PzFR47W4ssgpTx`vm8 zs9VGJDuNLP`21({2~wAEU$0Z%p(P%s5s3?`U;BcWY5-sag@f5CCApQ3j6KMTn>xn8 zbS-OaP)=94u`BrgV&>|L#ZK7>^g*}~FXpyrJx*eXjPYot;kL$;Lll2DCGm6L*1RMy z$SCI_0)DU&_z2aQ>^m!9sbPyZcB0cf0jp4`nMHbtEU)Z!J5fqBM&z?Te9X(-N0u2? z9vY`&z2%*kU^F;wg{A0y!F1<{#9r1*>wZK;jU6C1@1(IV8Qg6?ZaO1E_<^^>5IU%% zc|J*S*!v*avZt9rvX^4qb1SKLA=@deoupx;-tI@{*J z_Iku<`9;_;D>fysCW)+e9$Y68Q@tyS$IOmBGP0znPLg&}-%uEw3Pg;fi#r zW2c)GtiBMI1izF%Vs16;4KH4^Qi9jG_OV#;4NMC@Wyd;`5pDKfLRL90g}=DHMZko) zIMx?t2i8Z@zT1x$;C-c1%DXip{4xe)Sq%`*6*^)!yWJ%wUssk=+=9TJ#jc7%N*;1G z;hB(ELhV$uu&gP3M-)lkyorVnq+yEc6u5uI1e(SwZZPJ}0uY5kroSxD1Kd(8dcUZ& z18??(;2y)3%S#9{PU-&usx2f~K9C~xyuwDQzu5>njRiy@wfSUIB`zUNakPl4%6!d| z6hrTr&k?xPp%+kBLw3k77WI2S3u>fudY`#+Q`_3#_i~l3vWT}Av-*@Fpcfv9Gkrp* zoeUeSFiL1#;DFbzpZ6(AWJ8}|y#E06aY$f19!mJLr^+f`(Xd>$>Oo3tKd3l~gN>K{ z&$n55K40ha3ES>*0Ds);^00N-gP8Uh!tExbEI(r|n@x280P1mmWz*qMCFL>>Tjym_ zmEp+rh@>%jV7Q~B!vKqXr>SP?W}@e`uKxf4Q8%pQvp8?Rz&N8gX40jZuxLL7p zs`5rR-03_0{ulUX34ECZIXffC<2_CjiNbPz9{vuWp7V(J^UUfzkADl7(HG*^_H*(7 z033e~8PPrnZeu$QVOyRt87dz8*;*XP@#5ZjjTB5((XN5;+?y&>n zUw7qBsrO;3Sw^}*I;|AuOVf7v%50Y|EXz8E6;o8~XSsOQXjzk~jUU`s;g*aoTd#;O z0KR@8YI7v_YtSPpPLCl#v={5tBD0KL#W*^P)7&C@;9CM!D#>!kaL6}~$B9e*kw{;P z(`bnp7M&ka9?#dgYINjFUWI*L8#ols$BuqFLvwAt!9z5id!F_OU}Pt-n&_sN40HyD^_bLFQvcX_<1_adaYmEs-m6OeRvDgh*T64j{AD{tkQQ z7x=Y*+%EG`Sz&eYP+oO%t@m@l8#0e0WNa0QP{1TI#XHz)8rzfhF#-9L+PfS@K!jWA z6U1M11Qq=RU9bg1WA`iOEb@C8iU^gziA(T7c$U~eD)}}OCJ?Ew9D_>MU&QbPVGR}u zbpX>@G`iT9lnSV5uTPH5j=Qh#DC%^qRkYaogl6cgK1ZMKA#HHgN8E2UU5;@pW5jQo zA1H)&7%r0gHo)TzxeXsMy=2DwIO-dGCq%q4Oa;lclE$s{G2U6$TKFHSLs*p;rz(w& z28)T1F75>~At9z=bw)#R+6Fpe^g`Ou^8^=>e7s6ch>Kz5Y#PY2wl#KU*zZ$>;wO25+R5GRlZO&Quk}FWJA&hG75LP}*gFxIpXqWKxTKR^~vZkB&6n z^A1{t7kK3?Q(8nEK}Lb1B}Wu|=ZQgSn`#DPAUZrsQT-?H8siCAR9HTx)eZ0K0i#Nj zuxhQGyUoJT`iPUb>otxzO?i&;LWzUrWrnN?%VWgUtEACot>hfEVyE!a$f`atiU0Vw~5zwspmWA62 zBfj7jU)MG&m4WnJCX0pzI31AxpiSpY!iHfC`IBJ0F~N zgbRtNn~I14d5*ThireC#kX^=dR2;9k{Yt>M+|&g*4Gp9f62N=7AMS~P5wKr|R=_Vr zr{wHnf`J(NIa13AxlzWTUO_Zcbd{w0%Abk9a;h)lcBVYWNlc_gD&+nphtX;hu?@zl zIk%BW?fD{W$@Grkr6^wCQS&b_EMid0N!*s-9YePGPV5oE9l^PBTPpS9QE(&KM13+< z&>Mc^*!0fxhc0EqcqM%I(Y(|yBDrCX!_?R;ZE^loR7+FJRH~?*t`{d%~R6lLJ9E~si=Sedd4F>X8E%3`IvCh z!PIqTS$E<1baEhS>)dR|Noo)ejQ;1EB?7PF8~6}kR#dPt{-y0D^f1&{A7Wm0V~PR( zNo&}H!vWYV-Atd8{j%@&`@H`Ex%RtKvHqiRJoZDAYTjBU8s)yHM5X&o(Z}jlFc(|4 zN>*+Qk)dXD2cO~`M}f4FacO?5bD0xHq*ogehRJGC5Z--a6qe|1!OHOz^6s7g0N}${ z7v{#SQhp%S6JlAeH&l9o8&`0b?4a;SHyRFZjIxz+X8U-%VCo$0AI2zt$W}ZJ{7TPX zgRK6ff3k8<=uhv%v&KK;Ih{@ulm30@5$x^t`Eo~*?9P^>-{m-G6Q9@S_wa?Mzr>|} zCFi7~df&KpYYsu&G*4Pw^5rFzc5)&4w>XH!j}1WNwu8U~RWWN4M4`Hm-H$b}*L) zWUw27WqM1fp#k$QxC2tD!ABritT6e77Nsz1wNdI>iaJ4LZ>-w2j|L9)feo&&wNG>o z7z_g-Mh9uw5TxWXXwu<7A%}>BDjIylnNjum62j^B)X(G+$UOf5m~BNCR|c0;8RNty zR#k8VfHZbii*yqF0J!|>i65XX62dxE@^@Yse-Y=)1{o z8{AQvs?-hjruw{$@euouMYhArn28cIq} zXY+FZ0E9yA?&C&h$pm3V-MyIl8&v(xyBg_?5}5?!EZ|Vb)D;H(p3DMESx>ol>6FC4 z&k*WM2nE@aoDG!jpx+UyGFqrSE*K&=Ly_V8$OU8f1RGJ?jV6^v{lRK=R|un963cEU zB-!p;;qsRUljd&kY9nH`D)Pp50hT>!!mQ#NuVE!-!XpJZ)N9?G&Z4*3tG&sTtcNFz zxpMyi0-S0k7Tgr;B7Mt?2=X*BsFhoDloaDp8?}vHo$k-@z*{~8_?gB_L2CPkDNm@C zV!X?;sJ^-B2BRZCkGLqXUAHm1b#j}{*#Mut$uSMCugza_*xZ802gcg(ou z%_07}AF93%O3`4XwTvkEf}db^WfXL%ofW3r9j(3UrF+tlr}}_`B13K)D{2M(LRFwZ zTP!4kii+PwYur7G2L+sk>n#tsy$#pn_YDfsmJw(cVX}d9#+r*(pjyH!6Dgv3SwslH zsB&sY^%|@TK)-Mh4(?B4%SJR8w8PuoM_>#dy+?6Uu9Xy~*Qs?XC^83FE`?kPp+&Tf zTLsWc=n59(Y+nF-24aJt)8&AjB9lt>D(h2JCh<&scPsl6Y8nmIq;%@9?vD)+u?pSuDG+ znJ@hwb@7!H=F@1Rq*-tQaRf)#>MivLTx#E$Y(^@B=gvkF-$QJNm7TQp1x;iu$m5|& z*l71R{Gc|DGCuCP9#?h?@z|DD3kQtx$jlrE0#UJWq2yc@ej)WfAxyVlY8e_Ougon* zwcx&Xa33-cQvl~tpZx4l0@=O)0CMbVw$GJIOU5$~Gv}Cvf@-4Ij=^g+4i6%_RAr*` z7v=~h?vY{(d7y{7g!yS1#@j&bC@}^5^k;4KnW~k5lU_>r)cH z|^#s9k^HWD@A5w%q$OFn9iA#LJuZ!k0HvGjOI~X{h%nKC^>|x~l zn|-gf$)OqZQEkloLn`(8MPrrA^AWVH zr-%0qr^P=p();8Q-GSiW<_?T}BHR9n7yx6*C<3)nuTwDxLAR_F6)7oq$6vt0u;Q0* z`;YO%rr)SmOSPl)gngSu$)2JNZT5<2exQ7ZvB${QT2Zp!`wJ$A!u>=q1wnyl_?C>W z*NIdpo6TqS4QsP(0!UJxqfyMGbpXic3s}PeLw3q3z*_9K10TkLY(*#~E^%_D^?&yn z#R*Jm*tP6|bUXL_9%1a0CLtiavbs9(4a#0Q9eMJ6J_DZ8>sGz!vK2G2)@hvvQ zo&+=p@eaPGSKLC;zrg@D5Taw9ne1gp{vzz>@o@m`;rIUl3yh}4uegYcZ0bCmOJY0w z{sU&Rbeuq+U4f})y@Q?{|u;FwW5gtZl2zAG0 zjjo7-f|ufSm6DO#I})vB#z6)|Cx<_CVOQJ=y6-j$EsxYlN892f+69_GSg!PeC_ukb zx|Z=B^5V`)**SgWy+t{2hg3TFfpA?m?9fmPYF10&9D+x+5Cm(F%(%+nDs9-V9Jy)i zD8++Bsx|d068o;$!ji{+2p}Jv~x`I8vztMaY&7)2bpQh zZLv~tEU~Dhr8vV7c1qF?>a@;;y0te8xf&QK1iE;i>2$hg7t3)dQcay}CA1`1xQ4#S7xEn~vaOh3N(iMi*Dm765N z(FoQQ-Evg>&5UO>loty>#PglbUvt0L2k=`gDK74t~#gOnQNIDt+jC#yct!#6k00pV5V7-L+00IyXID}(=CGDWhpb; zD^AE4$wm8xMQdc`GsIRtB39JchMe**Ebz_AKzhOa39M&D(RiN)i?wsxG9Dm=q0@XS zP-LI6Pz5`E3G{7v4ye&dR=(2V60p3ljmbk!Xz&NS5T8RpOOGHg#jv^ zdrW7V_5R9fQagT+28OJlEh7m%D+D5xqFatyBxAC>}R#{a_x+8w@o7YGhe5T zLIAP&pnn+}gT6*J;-hbos{4YaN4~0He0m9zN+Mc$$e zG(8Y~FLE6+1{!V4{7Z{R#8NEUR zZT-Sl`nnnXKp3XkzcQ2XTu?>Wu-M-|C46*w&<|3mrh}tu=Ty#kN^jQ^yRPVum~B@; zc|+E`*Jo&o{J#|!@e_4$2c@NGEpz5o7P<{5r0hhoz_TBiUu@fV(!5Hhx{6=kLN`r3t-0A%4wOr(Pq@HL(z;VBJJnMC_FF;U!W!ua zh9L}8>`6k$GNO-RLO=xP_Db(+A09zV((9lz_?t&PUl0;_&m+57WImKe=2X!+1zU z<}8q_E&<+y+-VFgWa!$l(hJ}z*Cr+65kR4_i{va z#MPo6EV6g71^d}_*O!#vzDh8MPb4FN2&iuaM*R2wqoZ)Ij0=q?*eJ^lo-_SQL%Xj( znEK)thEm3^c*}*dg!aUVLW*R~qWX*0LuR-yxJgdK)+6+^doD87H3uz?xPhm}YpAgw zAA{3i%EQ0Z94ZTVzx)2CjWzaI2MYPk^DS@cbUcn^Ctt+sPCA-Dm0aK*uRKMm&3zSc zi$D=qkjzpV@HZVT*D+0CQ{2w?C~ZIKI^6{RC5_lq_xPGK{Qm%r2Ft-dWY(Rl=A)9u zpD@ehm68Iw4DHQdtA)7SUx&v+qkXxvi1u?GAgZ8$Q#BIj-2NP)DtSMYSx(#&@CKq8 z_$DXPJ|&;R{`98&N<-h{bjv5=cl(_`7yN&VyzBKp!#igW$1ls@&jjiB{{RW!?s@(> zBgw?>f0}tu^US}%lpcunILxnz&U+6(JpKbb8PPUgJWtgwUFni|;dqXdwKy)D{$Nky znh@CdP3o=`PT@chbVEK2;zYtl0|THw(7|&5000TfBK`nT53zcj?`3JCkqhPr)Cb^D zo+km8DNOfp5$Wbz0G0ZI3TAv#<a#jY8ky$MOajg=A$wZ#3yqQoFK#9l_HLjA&E zdGULK@+evQm9eDe^}%S2Wl;!Xbm%tavNTk?Rr z^26W6K}7N~tU+XA(BuJ$!|}`V_9ZG88#pIVxal+Gjl0avzc3v~7IH_EhAWbTT2Cqd zc$O2}32JUuga|Ycc!7`$+<+rO0qbCkb&#IS-Ggt;6FmzFbD$Lria#P64lSlPr;%!G z65_l9;Cb_#1fcQcy*$TEkqng#nEZD60g3bekL2tAZT6G?)_dGzY zK8=8l2Jo`ENPEYmrdP~}jI|-3KX$`0oQW~xPWnr%J zfTW`C*AY0>@LL5sum=j4%R6|VP+H9iO?wHI(s)8VT4CX9?f@Plkf$Fu)W1wyD{`TH z)GSRZ-|BhAvEw$HJeTzYWEHA?U#Yh(qn7+fNmA8tc`a3UL{si8YrTklvA1ul@N60Z zvDo36pw_{e6%_;Y!^9_zztp~sp5Mw68~78#l2F6zmw1Ik$;QgW1xk?oAA-;#;B=^QsOQNm~=m^cC4+IiRPg6wp|}lf(*54{-P)XjmPc@ z?H6A%)1TpsV|1_s>=MIWmx~%*=ghH!>r%OZX2vCWo>D~(Uzq1J87}K+K4pP8b9EKX zuwDy|M%93a$lTXRc%1}1d-Eu;ttvJHLa{sm>WC*ITs+0k&Ez7zvU;}qisr&R#Em#U z$#U^AWko{p4XuTlxJxU1!(M8#b$~Wn-bD}@3;KaazRgXmiiOE|;vo*tDMA&harj6m zK7uU{L^zy39KSDOQl-s`rA2V|I{pDbh_(0l9auoQWa2G^7qg2$%^73(7TAK{P@utH zPKB{o2`8ZnFax9&Nn!qD^inMfp=`S}D=4@m{5|t1Qbr$9oPAH2?3hEvT+3AM&s@r5 zs5jwo_XQ~>p%r1ka*PLtUx2T;pAZ=zR?F0OT2QgcZep2GpxvUWhFm>+8jSQeVUGOPap(7j)%oqMiq(lzzI;%&RT16npBaf+ZW z`PslW%pIe|u;Cf2d=c3x1EdTh#7aC$4I{q3C3t{~E0}rr8S5}=xlh4u>k}z5z})bf zRPdf~sJ$6cfN>bSxJM8L1_#U?;=|!H@WSFtX`(p{SehwC{oEkw$CCCFBA6IB=R@Ix z5-QD*JZh6GU>+_B;p|Jl{{Us5=3N>LYG;Ffp+!~E<{%rQX_z0oia@M9k4`GICw%aU zE7eX}-clbCB3TrCWYDuw-H!)r7F_;ffzh1Mc^$&GU(-6dbe=|@AY)MM@T2i?el>zM zdl(ba_=i)%r^lbesDsouG0)Vuu1puf7xaZt+m}t4ozIJysgz8)Pn3H*XCIHe>p#Og zXAj3O%iqJt@_BwZPxJnHgR_a{JAdUrulU?Dlbw(BKPdZ`;I0g8z;gcp2lp;~V3XkD zQhQ5_g}_^-jn7o9SxX3y1SZQ!*z2S&b@LJGQNvj+ODyS>t8~wH)XL_|=k6WAeCmCYj0M1>&+1+mBReZRkPPTTY^4JL8IVkvN&&?ShKvUkLH9Xi#Pxr` z1sbH{dWo`rMS;5gkQ1*M%(r_QvW2`^pVSo5#8wWg%xaXCcabZ-Zj6^a-1&X~08lL9 zOG&-0o2U&G%6gP@Fg|Jo3Gr@S`PoCKk_51@Z10}JI3UH8QCfSJneGrQDS{7?4CfHI zG~SPak{ z6P_kMA+>z_iEhJ@qmeJOgh!|zv(yg{5Eq=k9RC0hC%tRm!g&4?3S&KfEP0Df*sAJV z+;qK(IgzWeRbS($sB4g1)6}P^10H3d0gAfF49fXn)D8SaH*HLzmGu*idDK>C8mYMm zgF$o3180=JV)a);>QomJ=&UNEEdm{j<=O+Fe2}dY*_~cRLY36bL2O|gcP|#da-x*+ z5yyj)_c=Pw7zyy&*>v>nG{TiWU3f+(E;-W%XM8v*Bd$I+i z!x9pzw@o2MpcjL)n*-e#e^RXnVTwX zBOgaZyX}0+GV9bVj~U5n0F)n7RMz<#pU8|ucm4himUgHWDueY8Y*M;!Yu!K8JxvfG zTi}&O?jOJUigFr_CdXpp6SoOd?3R=pMe_5$m$6=kedfaeR;G zEg!6?f~qZ>2>=8_r;)b#m<_PnH{7~}ycI}`!Ui~KJ|ZRP4on!0A2AF+a>o|sx)nPs z9UaI>@i+_ig!vw$T47NP7aneBSC9ux%H}zNhna=Bz z&>>@(yJ_wrK^u^x&{}Q%mzY0821^@*A08;Sq-V-jmoLr;DBoAq4KB-2eLQ^KBk=>H`$3IjURAjb>sIbFg3y=8g!rrg%0wi zSEkkW&c&x$eSosHF<;p=d&p>M-|A=cMEC+9+z~z@^)+BK2dKd}84X`kPHqe=4W-ZG zAFXZiD2I^!lJLMRQlg5_5x{Y0?!zfy*=}46DX5K5dk{RXiTpqWFjEIf)$D<5*#yyN z`9qOY&$yv>oKg0E8^H^QLRyPFLi0>^UvmZL{{X~b4cH`p7iGf6m@_}2I{pu47IaS^ zz&11b&a;olFT=@;bF=(7%Vo_${2V_rYbc+A$Xqa{zU8DMi7GvY+})9{kZMv{$aebJ zk;~X#BT~uql@6!%V^K}ixhk?f#m0qTzz`}cN2SdY{+Nmh4`P;v5+OpRH3WswL-}4s zC3K5(bpyK8wr>{Nm;ho;Tp2thOkMr4Zj)*GjP?8vR# z+CoNkSBY%eEWEiucC}xqw^X&e^ohjsjW86C(8e$*#WwOa_c!;@!cIxu)7&e)HSx>- zZec-bs<^Kq0}|&N9jk(m+;UgA zv8n?x;r{^4ZIxeTEr``$T$co`E>-tM_>W}%qYBGqW3NP9@{f;*k98O~Jjx`7zWAsN zKj|$Nfw;m-9!64AQMB1p7d5~rrpkaMw}=b-*$_npFcQj&xq|&mK;+~SkocYbqt-1$ z0(Cl^;kWG!aroi*s#KsvsZw2GN!fu6i_;tLeC*2UlwpW-Nv-dP4H4^b9+=ENnneC%ZyUa?;08(kL}5P0Mi zTfMkU3~45XNZue0&|3gn)~}1ngD@2!Y9J6Ao{kYnA)07H5_iWk(RL=EcNzmn~@`c zYf;Cr2AJ-&w#GfO3*H%3DhwB`$=~j30d&;31_AkkK{6c{H5RR?k>DS{!ou&}*0Gob zg?Ik|vNuNEfc(xYL{Kszr}x0R{^t<6Ju=}+%KZ(4y850t{{T>p*)OT}{4rbN5j1B7 z-`usTegr@3Pd?);PS8zK2CBT5dwoZ)ODNe3o!G#+b^)S%LAIa650j#vUjG2N=;9tB z+f?H&P^&lhJfJF%iHHw5FCfcD%cyu<3a#{f#T_h8q76iKZBLTm+tUm`JLr|)s4fQ3 zKsU&6h+9BCTXh=Hq7QLm#V|rxp!XZB1Q9MW9$sJrX--OnGqzg0mr?3*Vx27}M;tDDoh)}WfFBwUZU4lFmIZ(Da6p5?wK}dw9qxBgB<+0|os8N)?n6h4J!Vd)h7}X9ls9f$ z6&0)0rTPt(b#b7i1!BacusQBnAj39e#0#1iSLzN~`$_KQbR7!=+*)gb>SECv)$BfQ zF{U2}n0W;_D_vo*jeU_#x0mW*CPEa?(&C_z%zl!H!A295EELP#u*b&6LZFG8FmcIa zK$KAc37~lVH#dvwyOh2_!NtdIN1Xz)ygXfj0~@fe!G|%xK{i(!jxkfnWf#rlysFVK zp0)T3Mg(31>2!j?KW^G_G&^5=f5|vmg zpi(9NP+|{%5&fM{66(B_8$2Ph5z}(?MR!lk2F0Q=1yF1O2K>iS09R>t)UADj#JS|b z+PqhFEunv5E;T{ zj!18qW%_OL0-501G`pY-JFsL!~(VN36uFm5BNgIT3puuV<*eT=|X~3qE0+7I+}R zZ_Irl9sXikm6sKZ1Me5gMf{{TOZzkiF<>JOIbFG(#Qo9Vmi7qW=K9n*HV^FCuA;w0V@F+{0}Q?*cA)bLD0 zVD1yK7z|)?F&yn?=f-A0TXr&6#JT#EGf4bTFUsN_CyeHFea}C`$Mebgo}tt6or&W- zk^caI3f!0VFX~^^TV%hfe^UOX{Y7e{(USh9pAz1pfod>vDzZ6egr9H(jbtOei{lg& z6KW|3K}lb~Fp}w%W%du8uXi-A2f4d*Nu;_}@X=zp7dJNupa-%IRrL}AQ4Akv@JDa?aUq-T%e^qLU&Q^%WL67Cn@FeMiPje-1Ni;=2-YUD^D93+uF~l z)Ic}iQBJDkH?SO4O*iT&f+;mtTo=@a?6&b?Mb=Cve7st->KRIIa^=5pqG6l^jBuhj z;>5ySEnE@?r8v$CoQA{VCy$7XGUaywhmPzS$THw~3bI`RiF7SCA-2s&JE&&cfnfy2 zCVvUKu`Dh2{{Yl|6rzK_{ve}!luF%Lc=VSLMC~LcD2Lq z+$VvQ5$|PYs*G6@u+S>uKoMcbJi+X`n%*|sWuvv?>NF(byWO4Cnr`>~LqKn?v8N?2 zWfYB}Q+*x(0C1MozQL~=M1`QJnj7JNQ0~LKn>N;Xso5OSyIDvziGPJB^9<3epBRmt zIw}wzP8aqi4qt&$MRQt0G8Ef^i&`(a;4BKrMd``e6rK|~q|ts_jttcBvM4zG3Nz*u zp>;YU@e?ES{38ST4!;6$%DkE%hrul7d=Le}IG+UgAts0~P#&dyMGj>6A!$;nQ{rJk zMn|yxYCJ|OHWJljqtEUd(5mwR;C(=yuc)T+E5o(sWwW4$N^{I8c4@dDk2KD zKU4Jqbr&?SO%)J}IW}Rb<>FdIIZc#rz5K-~QXE^I@G@fvz`tSiL3E6Z{lIx7gNGn67lMz)_B-%2XZnK()I``6hNDSorp@wc_jM~E z7Cg|H8AAKDE72-%#6sfLp?+hSV5o!2TxXaK-eo^0iBdjFm$@v>WEe||d8p2Iqxg(s zj7CchjfyHT0L(*2%TcNWskv!1mo1DXW3G?tIpCH%R7BqsOQE;8XDL6EWNExP`Go=O zT7iDZg%xpedr(VG(Qs=?^V=(jT z4`{|hZ%8r)c`O?S+u|jkABzJjoljC)&dkq!&M^JcdRk;S5LgOHFEK*Bo z8$8T}ge-z+p8+ZA7SRD_Lm!J?jr`{$Z3*#1UG`M;nuxXX0YetgiNlSQos7zfUHr|L z%A6m8CI0|O9s&}IT!`PM#uJWQ@mQq#Au9I>+NUFbA~Wc6L^YkLL>a4gGu2v0m_!!r zc8n*6iB&wFRKGDpVb*JQGz?pH8gY+UHS20ePzh;Ok*u>93U$MRR~U8(pmwZsK5-ey!el$^JfT#h4yWd-wp`1UffNW4$t)j)d!&-$y5UF zevkv(6euqNV;$HKVyA}4PIVpX=#L%S?utZ(~IXvSHN4oOA5#;E$dyr%| z1s4M}0q;(DQA8?2H zGgCN!5%l~B9_0bWzb!~hF<3)N9n>SwHfilin8*+FE3Gk#1{c4Bk>9$(6v3E`cRs5JPW)cjTSOXuJz z-JCxcY1VT4oc^ZAulTfL!>kqdj$E|8Fs+8SOld-aK~zDUJLmE6T0gamm10^mU~oQVylKA2A_6hS-@6QGIA?mlJ-e6=C|tUlY}&5%jSqx$94?~_ zvBT1G{uj111$CR2fojnW9b9^$f(zO%n-XfPxBT;FMUAm zO9;T8pT;epAA<@H#&L#f%|SP!NP73Lb81i@x}6q`xJI%M)v^9x?s2Sl_(NXRYQEvj zD{}MS)CtlOR^|QKrFe)|@s5Vs_qvlfcSB9353wK32gDHc^!2_vbUlc+O zes7XcjpOOETCYbwNGv=}d?TWkj2UnP;6<~pA|kGgmP&!5HqPwvg5jtd>d8bjqFV;7 zfS5(U)K9(_HZfoAQq3KgE=CAtquJRwexX$le~@coB2@96k<~|w*eO@3Q#OXQ}Saav!PdbK+In40k* z)yc935k#-6WaC|zNZzSJSH47e$1F;BQXHVh_*}z@uL<(H1O))1g6dgShV*V)j%aIT zm*8J)r=Ut*EX}VoYCT3Pbknhd?ES<{`qBGDTU*dnT}sO>Dm{b_CCXki#?#yd*uN36 zbX4j>tUoWAQQ)tH>;sX6sN;}myeY3S6`#>AcqKm2anSf8hht*HV_-H1ptXI!kFSLU zMjK(HGyPnuQvj4wDevIN+}I)GN@s`yEUB21^O_!^j1{3dH-Le{P?3DN{KCDK7r@tv zu=5W$rEhN~CqWa9@6=MzA8?p9*NBLB;V}rLgvRhGi8b)c!F&3Fn=^tX5L>J<&*+4G z!)DMpfO6pv7y#kCS&7=uu^}KfEqYXRc^)H>20da?vVwg%qAnXo{VeATo`+T?}zp3%SL|CFKc*P=A z$TPxs`kp_5q_ZB4Bf1hT>}(*p*(RW(It=y775PU@;3Jn}wwY71!du(|?s-Y@A(Zk# zy9)flN3kwI9_7GWCyOsxZ@HsXO?-<1*u|igleuxy{lv1!K#Sf^Mt#GB2#JmSMAQLo z$_2rD8Fmn;EF9swE*Fm`&$>@dx58d1YU7X{Io!3%nAG3x?TrL3!~g_fJr) zNDvn47lJ&GYE_2XbrjtI?;&ucS-9~kLf`C8#qBl=f5fQajXqPUtkrpNSpkQmJ8huE{ zVVeDof;$H(O=5wL6rbi2D@!+oHSL|lJp~6-ZL4X<7zsKbe~ZcEe5|gAD%Pc#97O}j zY%D%hYWZ%V5ah)x1Lhy1Jg&CogqLd~7oENAtU!V<#1N=!f5dI0QP+N<{{Scf94n+R zqU1bU&`p*UzC;(s!Vi|~g@ zt@wpd?$4D$EuXLWKN0>YMZ&RPb_k``_HczM0ZmF&Z*0^Y$T?7iV1meUtYeN}iCaRBat7mAJ|5kh@Wr>d=)GYxkL9!P9DP)+w7xE$J-}u3;EZH zoYIR@!~X#HN>||1?0KD-&dXW(iSHsZ^E0h36u`&XiF4o)foJxxV-oDx6)e{tTpG{R zy2}2An@FSSDkwQf=?#H=5sfGX@g8j|_3BjsI}gO)Dz)h;s1%B?btpZlK8y+@Q1uB! z)O?p8D_Z?cY_vE(B=jI?sYHCBf;dAUu0J7Kd?P4qvO7kLSwYeRd7>ecSFa8;FLhBY z@0Y{kZ((^GM!PAH`51UB@U|WyA|%N8C9AP_<Qyg|E?fa1geQS0;q-TmI!)RI7_-N(KAkcLn9#{^UjwRyE@JGmLxf2S5Wh z8;&gh0IWj9R3E}w{N5$6Qr*Fa+PfNk#~ZLW8->g^2Cton^T>Rq_nT1qgbFSa1{txj zCzVSo$Rx}3z2c&%6xv!9D)`w@TOa!@98rsZP&km)n3@yV5lk$7lIVLL@BaWG68mMB zaF6fY(CgH8z;0jTM! zp2f-*>V4z7tBk9@%NZ08%=BZeo_zh!{U`}42bE7|;iAI$QyZ$L0Mbccf`0<4ff#_CQG-tii`7~ z^Ao!LuRi70-1@yUG=lo0QpdQz|mM7>qT@btu)9L%jF0gHWAA5d2BIx)fPRE8;iV;@BDjov#4`o_0>=z8{_LuRLoR2!lDjc1R z-I8_WU?pnUIE&Gn7;4a2T!(`#aWU?gzo<=Cz%ca=E#DB`YP~}_DK(VU>)BR#K4)VL z5pF?IRBhx?776K>MpY`VT%K7sl8h-G$StYG#vrPp#swC0+}`KKc@b!6=1lQSM_tn8 zcrCD^SUUrV8$8PX8mxry$GrHAYQIy|zQV!bfDjw1Z^R7=?^4gSWm@)9w-_9<<)g#f z90N~rfI$Z8<%mm^6Mqt>7ahs$1&5OUVTUD_tc^Gu20oy7AU0&E3boiW@*wg`R2i4C z&g9I?E?iQ`_Mdnt_K_gerNa9$i;;oafqjEWi|l6ah+0Hc>plKE`ud6DTM)febf*18 zbevnB<)V74W$5-4iluv*qb1Lf!PsPq1==-#>Qzd&TNIxNrK#M~#0Cy%Ld>O>e=w+1 zC?^Jw_(IlvR6;cEUlO+=sLHQ#a;tVyGbZ9`RzBAd&%~>IKv)SBU!8#<)ix`kf4CPi zEP%?>txIknsHvzIy=Bz4!U&y!avP$m0Dj?}fc8FOEg)E}s1vFJtw>aPg$eM%qPf=kNu$rlu51U^%=r#OUG>=F7jRRXeyx{dZ z%TOj_rNnN)9xcz|hsZRQ2iY8t3h^$yO1dy5C`z)Ny>0uOH7~O7!~#=uWW}N15DG-T zn-6AzXM|Fa;*ovm$hfV|SE`nmmF)ij>Ft>ejet}uwG)_`Z(=fLr>Y}EmsE_J`LcNE z+Oq1`;Q&2paI7peh%kgFr)djx)BHto)6bb=6l3!!Kb1;C2+@9{fOax8DUL$rZj5^S zk)Lsf8p!IrAMREk#Qx;E`islvR-R=lmV(kyB2|brEXi%^ic#0@V_|O|xWj+p$dcDg;397+1(6S+a(P@I?xixfVddqHjPOg&GAYmk zeZ;`Reqg0+ToLTAs8e|uWN5uwKEwxoau(v&(EE=p4_+_scu-(@_ zBYhl0vAIkX;Os+dDSt?yNg~_;Cl(MSec&D$bGh)tbr)JhkBfu_44r5|`RKF_#`a5y z@e>HSG=MGsB_r6O>lJ@-YAsK3feN)e2>6PVFu%EJC=pC$@nIB=7eUNqFbUwHA2p+o zr;o?4<2#`IqN<}hD#>Ss=hV|s+Kha;ftK^sxsEmK|S43f0dns}0|4hS5F~0;9WmfVJR=m*ObQ5 zjXQGCTi{d;pQ69+7UNAt>94bpJ*eW-S4D4nBkuxQ|Lgco7KLFGfWwEx+{4PGA3z7Sj zUiNs%eZZolQm54)K?p5HK^WmJTa2+}F6s!WFt<2Co3rth)Lc6|aXNcAdM)Dp%Lp`+aSln5^zOM?aAhE+0;y9oxJ zJ#{j?tnK)y=EU9{diAgji(!@SA}}Dr!KN$2@ej(v*fSSP+Wuq4<2Db(`DDtkh!o(Z zh5JSw)I)Iu)ds6PPc2=lh<4PWNQb@6p!$Q(oEyno8rBdkE75X@iCYUdvWf&KzaXd7 zRVO~o-mrGzJ+1sholKg@c>Q7pTo(+D5WRdxZ67}~!@iLVa{;jmsNZ6#N}6^hO(D3d zW(yPOgcWn~cb22u;yN^f`ZrB|`KUsFpo%+iafR3%QFnQh4Gfy}{{Ylm;rgA)fGeJ` z<;3e%1@G*x<)ONtm+AXAD%6N~nbn3P>aV&gr*RBZPMBdLTcHddu# z!nO@;GVFEFm_!!}ggR_VD|esnP&joqsyKu8gyBWz*JULe7rt*|efnM_9rkdK;67(! zWKD`vy!KLhF$EvCQ=$>__=uHB4Gh@nRRtuX%BlN}O|*Q*tF5etNknqi+99uF#vTA) zU|6t(?py{Z)SgjLhPUDaWAyx04NT1@ElQH<0;QtmL)xaN61uWi)H-B9D4#kD)MB9m zHz&;orjdxAXT>bGr13oKAUJREg04R3_5v+{3c|24a!Yd$bAzyyT4haiz&CKNtJ(w2 zHZPdEs%TEXYFVr1Fc&9_a-uChrYmH)BhW^@DsvOU4=(Pi0<1Ajtbpx9JliS)xV~7{ z%fHDMj6KVf3fQkGzuFeCPo#cNvW%^A^egWVFFvKQ4}-*Ywb8H4s1tu^i`X49Ca&O! zS8bkqnuzyd2!w>l#q9EO1$r#-Vt?b95jn~fHY<|PGbJCV%xSW=z^~X!uTuwqa501h z$HLX8I~jsfF(0!b=W^F$fP_mFk)AuY<8dp%kxqh_2KX7n6 zXr{cLqJUT>l}JRFagDIQ7H<%mrd{zq-!4DUKUQ?XwFP}${{T|vjaB5fg@rMyXKwcl zP4O%e{CvV}2E4Ej)N01U$`8;a(9wi&h?iv2057m`m zT^sQbNOvP23v#;f{{St6y*-Q${jX53eNj>=(fz?NH4o}>c(X;83i?AnIEVDglhpoV zevK@9hB9w(bfL7w3?)H4G+EF7HxAzm;yx3f5y;&#{?UF@L?6DQq;Zss4^!h}Rk$pk zqMb9~l6&hw~2P?$`i;q8^I<@Y#!MMLUZBC%5j6p(%cka$?h8NQG-tc?j! zC0FhYR9{5C%c_!s3Y6vb3iBxc0C3V?bZ6;I3@TCa3>8~m^Sj5`XFpq9r%xU4tCBa|yw<n0QboY6$Bv-pBHdAJ^~Mfji{(VEf~7~2AheC30OG~d3tLq+=?xN=&Hkb6d(5( m`KPAN>|$Ast83KgC_L1Pueh|Jx#}$IQsdz&9^d=?fB)GyGXtXl diff --git a/frontend/public/img/template/Foto_04_2400_small.jpg b/frontend/public/img/template/Foto_04_2400_small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25e319e22402c5dd5d2bdbae7ea98c502269caf4 GIT binary patch literal 172015 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

$US#>GIj4rp zmly%bX|=H=+W7i$)ptv?Q`BrX`>l`FL{xOwDTeUwMUSR+z$(dOgc37kg$O#fxdr@F9{+vUsIxht$z(jszeStSz@S~*0B z9;x%Jb@J*oSwQ!x0S`VGuQ9fE1N%e93q>z}@H=KuWEEmR$-#DxI*{trA1W_xaCb7~ zH`+~+B!0m=Y;Iv>FO@hZBF540{}fywMWUP>*!C%#gAEOxQJj-#%?9^|{hYlYC(Qt` zkuirVGS^7Y9w#<+#;1Hft7v@hQQ|vyNK^p3VVv+Jk#JlCeI@SSBnmevQ`EOYH}vw2 z%N(0V5z&z6D@ZqX2lcey&|+Jcpk!47lMtkTk%doDl4=}$eb`?~jUC_pWlh+HOAg{h zE^BNsRL4gsKju6WsHN)qChQ;>@msD2i#T(30>RM9oxm9z2_E>24V4 z;6v(oK#Ck9o&hmTkESmG_)ur>EpKX+ss1`V+}rJTPKYh*uy^hU=LhFr9!@Pm-|&Ps z`>iwIRX{Scq6U9EHwd%v@XU~oq_GAD1MZOo?JGrd9vkvGUhs>S(bxSzIYdT{*zuA< zxQ6Wx+|uJ|6Ew}-lcOK7Qe?wweQM!rGWP4EIsUB$=HCegkEz2Mfy8;#Z>Augd9ptt zd}#_BUGmS{?ptCEy@(&PHF4q`ACN^%M)NSWRmPgbMJ8<*t_QMMPxUWS7@}5FpNPqwKX*}6LMNH< zcIF0?YElMu{I`HbBj8x*k|% zLC+))V+)-7zqaHp$fro6OC^7Y)kI#avRchsrQ6i)vCc`_)R*|JuD8~>0G8%@^iHgy zJ;RP}`D$f?RMk;xPIKoXd4|t}-1NV)0$q8F>}LeojgE7jfrvGzrf++~{8m6mf}%zE zkuJo6Tgm~<<`Z!`!h$a>WIt+;**&n)oHbA=*$&qiJ*e~HvMiq#%zi3B$ITzblzm#H zDr<#BiIHwlLGzbRsa;cWomuVk*eL?DOErRS$)0e5!1d>uJR4I13x28(qg8&Rdo6h+qp0yfyi4?org#luHl62AEu9k3NoDK|j58 zs?RF;osPrB#@urrsa|-%0hv*4V6z<%OAS~G5Vc>67KAmJVwJ1KLnfXPY2zF4B&iP> zf`VU^l0zcy_~(C}!X62Tn*aC0_)JYB6)u$*kW6q(v7fbV68DlFZ%V|4_tfo=qxtGBEsqr}_9#4sJbprO&K5(Z@f_j&d%b?{U?ZaR-RZ_)2i%nM1 zGpcI8P2d}SXZ8OryG8buy|jyTJN=Q+yp37W1j*-KIs2^{bJ!m9%tMV(@D}jN)io|p z#1ZUH1}ere^?S*Rxs87h6DAap`ZTS*;7giDVk|XRYB^?v{XIXHRAM=KKj(w@CV9E} zy!I|azbrRgsl;E?6N(Nyf-tFo08?SQfQyWRs$NXWi<(^a(DELj(kX5SKGM8K)==yK z5=$RS)qX%Eo?4`bMrM%A&df%K$9t#%(WYNI2_wF8k!}+!a+%dN9V#2tIFJSY*#lUd z1OINR5qQ1oa+mptkh>$4qrm1dnF*%|xp;tQa=$#r{n=;2KhHMWViQ{HbquxdYT|zm zXcAgdm&>5&f+~Y_bGtdvf$D`$rh72RGxzey-QT2$g9Mjj2X0C>+t^(OT|ek{eWe=J z8WzbsHYuQLY!soe3G+n}8Pt-GPg`daPGdXoN+FbC0QZp*n$79=HGiw0G5?ATklxm_LO5a=JvH8V4rv1ZGtj1GMk4$6e(Xg z;OT5&lux;V2HG~>)kVO7^~G-rC+SqHMm6S2#6F8`Mrd96+R|*5Td$_Q%0Uu?RDYsQ zshw=v3NKq22my9Q(t?`OPtM%Yze8BiV5f|@kF4%9 z7%NwiH(6Hbig$UC7H`7hS;;v4N+8Tg1{i}P9W}F4Cc}9Kry*m$e`HvF@a1`YzNwks zcuZO7dx z*%mdrLp_a(VQ{p?Iikc5hLX6~-lO{r!|p-cq?32;nBN+rbEBV5Qszy~xK;f{o#%2V zZ0a5@n(qx@^l3D|ZAhSwDKD z9;6JC$-f|VZ_P;w$OYaN*JX1^B{Sp_fd%@h^1 z3@kFTc;T55auH#ZFHlK}@G$Kird94>bXwsdYHx`oKt8Kp z*gR3e@m7=qmo;4UIiz+oosNcHH0{!&oL(RweLfrj~1QeSMXH4u}VgTH180 zs2Cg4jUD&Nl*a1!j=Tj0|9M5JyFz^;ZIoUbM$O~O%8m(t&TLdsPhUYR4<_M}bc?EG zY8zjtZBM!clONgawx3|_F6o9yr+skICF^FtH+4KN)xa~d*~qfif0rDu@@}6Kve^3m zwryjSb&U5{p1B5cO`;2yS41di!DfeP?K32YHRC0$6@p2LeQ)B9+Cj(%++_6N#iG3c zY~`FcYF+HX2-h!=cXcUbzs=+7vpy7&_dA6kDhuUH5og_Gj}R(Ce_p3V+9cZozUa7L zbg4$(Mvl}zbp#`3tA=NK5w_u^2QuPxXOCxCMHeJG#?@0}u0hT0nQ{sjXWKp{xZ=^z zUo}z6P`P19xCQ7LL_2bupsG-Lh&9;ciMRexh6_V`Zun%jihVckHnhbIMO_8clnNBKjXT4 zCtvUo>7CRkL@md7txX5MhjMS!@*Bnd@b`x<@DP_0zp<>Rk3rsh>k~U})v+E1lV{OY zp-I&kc7TKi>0Su!T&k^!xgBwjCB_$PS(6K6Fk0KPjUd|cb9hTG`;CkZ`)A%qCBWQB z={uZvvdcD__GtCNw)hh1e1+>$4>cTpb4v^YMh_J!@xVy zc9@+m7zUD+d=5iBOC73!ON~^99mM&1IaJntB&;zrrbnYq0DYsc&VNlAjD5XJhU?kB zOAYebRc9VE>_{3mWIXNpW2m{mJyD7{1WyPZ7!k6tLpD&3T%s7+qZp_w2lmZ^<2FeJ zU46#t%Y)qumqZ6cgXaWolssF`p^(dB^!gss*R&-qV>zKN?PXAM-OR%edK#a+<-CTQ zj3d4dDw+>b?fBY#;(Pn7H%pjn2V4tCBmiQ<8AR-+_4!!sGksJ1=_*qAXEre`(JXe{ zy76+$;BN%!>+6+uiao$P5Xn$_!mzdj%4$f)5oDfbNdYf85-iQ}XA-wu3|4A6m~u;h zz?)6g0jLdlx$IbjN9a>e=waj|V9Ru_D)Yhl9BMQ~Uj~r&i;2mIu*WpS)<*15Bi$db z&BU4(%vJOs^3I-BF|W@Z&}_yv;!5gOg{+YVLynUpp`%Q;*i!5YQsq=dWTVC=sT9(9 z#_h{!M-i81uvm*@cvv9F-hd7Rd=bG)2lC9_@>bF$Hlvz)XZgN*t3!a!fl2^ZTp;LL zxUHt!ytKFyn4*8LptCv$b~jq9V}UdAUNR_dtfp-G7_Kz@=+f*9>-YO*1s>p?ZZmgt z-^Zd!_XzGci@-ci=Q~_S=~M&}nTo2iC~VI_VpaB_Prd{$q0?*SXu|x$hWp*$-2-<& zzJ}w^>THsp-3tkx)2s0nWM8iq+(2aa#aHDf93f-P!!yXFx}l_vKi}^ugWLRM7~(n0 zIc}pa44^Dv+Fs;)qt)+*9 zqOu$-23D!jcCkA82EYA-K6WPbrFF$5u*4x$miZ*rG4IBWK;Qc2*ak02RM|z=19XfA z^?Tm^DE+{TlY|t{9Y5n;RC9Mr-uqOzLd+rsb|#2+!Zh%%#(qn;RZ;yEb0XFEFP_Q0 z?~V0qFHvW2NtDy3v*+-pK5`e?8cNu?qQlZQte*R(i!`oG7kZ+SXk#)sG0SK0-YW#gqirQC#i4Pr?D z_0QaQtphaIrI(!r;Mwti_cc7%X{l6&sU*5WAT{v*SrEYYK@HgW#*!7R3E-7dJ*A*} ziCA=*ZBJR8n+o59-n=-=w_RTMDukp> z`HD^z)O_c8`W~*YX>qqKn2sYak z4Yx!#ZR_%hfS>&KK|M3jSYMoT4g_(b>G{n<%NB2d`-CJRG-S1z)^S7rXiytKl$6Vh zI#MXd{1o!i%bc(`v!lw3nY6xKr%fsNeomfH{ZLT({n4zy7D14!9AtSzqDzdMP&-Tr z<_rVr681#@6kDIP=^e2aSuqmp5kc61S0dQLk!@xWVQty>91=UU58MMtxjFXI`e*xK zWcaHBEehXUo>G#2>@2v{vbhN79F@9wPh;KxEI9PJ2({sU#(^g2QuHO3MR<}PIXLUi zLB;3f9~p^?@3sMS|b4IS$B@ z=0lXEhy&)}<|PremU1G69XhD-$#)2^vD+empvWz%Kc-Q6J#Ui0?CchsFU%Ra@0ai6 z#!h}fWeQ7Oa=d%HvL+$M|15K1E|~c_yd#TQWee6NlS(Bf2_D9J zO089=VoiDW-ZmNnT7t|_{Qa&f)eWw8RTd9oGt#@P{mZE^+Uu204a$97h`nN+S z#VxjY#ubhsuEleIwYKi~UO^aj%ag)s7!G$rWTO>pja;S`Mc!i6h9_MNSjx7WySGBx zsC%T>7hd#rxsrH4HR?c5&M^uMd6Kxwar+vvNtIfk?=u~e#`3xk+5IUIXZ zmCEgv1g&^?vEF@l#5^=*c~t|~I9Q*~NgV;!ya}jzLP^lC8^*FO9v;xGSPX4A{oC4< zf}V!@x$EG(o^vOpnod!K?Gm)p*fw%>fbng;)WA)M)z#-SxU8_`9|(Rb&)xy~(Ao_D zc3zWUr`GD5)%H+(E`d+W$iD>1&9~rU3qKn>{w{6Hl0DgHtYCl4MM!EfP~G;~$j+da z7up_d<8U17aA<5PsB`+gEe9f(&+{e*=>>}wmD$|{d?9PTWw#UENmEf;`2J4;xtoxW zv*W|}>HbL~(11?+*%Dq?pE%YkMMbW|$3{FSBtLb?D)8|pB!vpTcj#zXY+qpPQpQYs z`L^%d45V9Y|CgpLvM*qtsZ$;q7!)AV!wh^VWZx3rfJGO)W?IJK08i)KwI|>rLNcVP zE$&b$V-g7a&=(>t#t8pSD*I&X&Gb=d1+iN|`Ah#($as^Zk%!A)P{PX(Xg|W>qjNVc zG=U{sGu*OY^$$4)oXhw14o>0d=QFV+S3F3aq~PeM;JI9F^CLiP>@U-(Ma^It`wS&CC?HcG&XJ(2bw zbquvT7@g|ZO*K$DaLy&+#ZI!QYS+J8+due#7~BO{cgJruGwF=s(8)gpln0J)Ae)ey2(Z}T z&pCtp>DxitYQvDc#8wG=X7IcA#g=D^SI~ons0*}sRkiyOs#}5H5f;@LfwLyVnpK1k zZb7BIRI!m3YfCa6OR-c)Yd;W}uzen#$`{7?&Bszj0{6V0(#O~-T zcKl^q@hJd(PjjnpLAsY!qC1jOb;aMvn2T_(rHQM(uGe`d|s2Lae!`?PpemB zkgmm9zPL@Znp}op_o)ojc*6k#bwSf8AP;=^Z z-UL{MdoEn3cl5_$iz}MzB0|905+n$<`R7Q%3$T^HF(+v`4cT*CB2E!C`v|v)kWfKz+4gN#E;WkW^5t&78@r?G`atW>c2|uOFb-$|# zR^wPRm_26eqUL8CX+Bvs3W#2eE8%e}g@CV2C7d_OY;L%S8%*8C+*m2%x`Pbik9KQo z2s%depi!EAeb_xNHaK7IasHt9niSBK^wM^L{T0WmQi=+9;f8$%apF1*wZ_-h+Vr?V zp9>PFguOipxk_Sf?@jGK`K{RmHzist#J^e+pA{UfyUmPCGAB~&PDar}&Rl9rVpp`} z+RagVHF=VZyQzMGWOP*3f#KGRkbLRJ@7z9>f~y6OvV@)12g_%{V03>^O7%ZSt_}=8 z>Uyg{&ZxVu^i(I|*b3?$*zm*emen^A@X(-!wEq2@-jx65aW9`Z{7`0Sb zmDU@Lr8i%FMx_Q2XgRDFbyHDrY;7P(ttv@doIHE^-Qffdl+0a2Wik?8J}c_Nqnxl z6As9eVQ=T<`l~e-G!_I4?T3NfSS3Gjud5ZdoI#2n48MD>K(eVlg73WwR3qR<$k%Ml z^{5YO@CywtH(Ik5rQ!`Y%pPNgQY;1odjlr{!4rf{+f)@LF{X6PDzqt$TlUu#fZF`s zN!#ro)0+os$}{(2=mQU>US1g$Dkxc#d)BrSuE1D9fWhznY#{J`aAjRUwc4dHVcF>n zyhEV#sP~w#-E39bL2gQ#)O2y`AJF_nsK)x*wae_g8iLoGwru?6-wO4kEu{R6u`?FK zz)G3#Pt+HIpC{6)P~wy+iu1$m!&6`sqnISw|~lMG#M356FZ z?&ZcEh0~T)qXXcQhEh~K974@;^Hv?*!ORlTQBb@RAT$1fCRlu61=ZH2NqCYv+L)P! zKa(1`CM-i9vFjupulP1eNQP|Mm**>w&;I z{{)|OBorRrc|Mb?Tlp=JD&?3Nb0Bto#ycxjUmcBz#7TVme7RY;GWUYAHV3pnTOw8F zKa8!e&LrGOiDWmdU8G^7pG?%0+_kOOH}j<9pD7RZ=uvayfhiK5{i8r_Qse9Sz!K`A zb$2}Z&`ev4l&XOHJVye9dSay>k5rq_^3=vqXd#2>+*4Kb_{G5jwAwy|6RE0!DIm(H zqB-Br5|NOf9-!d41iwIM=3OJ21`@l*cUYoctxGk0|1vFJMW~zGI~o|0agiNAZ}$VO zI^h_Y+g|2Kc>21?mKhX>`h@x=w5dB>IB>DlmL-@Z3wlNj40?A%(-KkznI7*PNbSYP zmYJ_UQuHhw-<&2*rI%)|&eTu#0RX=JcGL!<%m9lpyK!q=)5s88-M9Yaq*y!F8uKCi zMyKQ>v>IedLr5793&}26ZDn9QCNpNOrGIuzM_xj9_XL+0c>~*%yu}!2a6#PPZ_6ph zEj1e-Eq}V-yfBf$59V9BH2?GO9@2i=#iJdSh&2Dw98CP({8|Xsg}lfZvzyyg<)JC5 z)ERwmwHXrKXdA06chH9)jx}|Q^;u?&fPXarVS$3)l?nA`+OG?Zw``k6m+Qq#w!>TJ zcTe^e`dF{2zcD>=NYL}jS01y&ia@w1{~RF>x&}`T7jaLl`c4rcOnk?I#z4FT9jgYl zq~@mjPJ|xLv|4O&PA25OCp=e9b+rn;`+^8RNfM7n#F83NY7I6to`Jr_+oieq@|D@| zVvMCHns~Bl0jpim7X5Rs;lgT7JhaDYR<*8!_4Ss3%+<75&Y}tuq-=pt@Y>ozrxFd9 zFmvpKpwRPJRBGD6)Qj~+&h8F;Yv1d5D_@>joa)M)-_|#%)rbiDXJv{E&&u}C+{9P0 zPTUfm?{}cr-})Xn!z6DS&d%)k1K7)s1kvD;?@^vSjQ56Lo~XBKhq>%L2>#!+H)D-7d~ zHI`3iv^;nOG}^4)pi@#VS5bQ#*0)i*Kj)g{-UCg#-=fL-UzDf?_TlnH|eq6{&z!W*t+*)NHAZQ|Ekt&+k88{)aE_`+2VG`n=!Q%ZI%`GXUOo8*6a6gHe5(GpJ>Ml-kpaVHU7ZWUvGk|NNalakeR#rK57B)?ba@ zx{Ue^Kbdrp0WK{}venN>KG+#~-~w$%Tt-vL$T%5aWwRnW>Cg5#M23t^0u$QIdwwUO z5zy1%Z_|7*MKuzR_2zdEGy0^4%b)#nMpdS-0(3+M14aA*RKBquR*Opc29Du=(ZMf* zl_oGC9n~_QJ$Nc&j*5-D1%EBk@}7r{9>q=>#4MeorhO@AQ4g?O@UQA~^3^s+9x{5p z5F+iea#Zozk~ds(u%Hbbp+9u7*+@$hR{jXV)Mt+SPQx}e5BR2DGFDc2OCj1E0pi@d zlZRv_#thxoHIzhZ;Ag7E3HS5FnR4N76hjR8%GlQF5g@RC*Xz;7$yp8G*{*H+*k*q) zDZOiRV=hZFbwurP9o+u_IpswC*G`|HPukk#(>l2T&v`Hgv98R$KBrARN1Vy>8+_tB za;y4gc8b3ysrWkU>Xa=+rrUDT&~?VY=oR6~a_j@BE~y0BsSUP4d-$ioE-!fEb3PMi z%>%Xw=A+M(3EirK8!t32b-gYuxyEm<-mv|j5R~z)8WvpE?>53v>w3d@hW$8Q<}W{I zv09if@UM17Ht9j*(I4%<|DhK}=Z;g8Rb-~DzxuD<(dzd&S$R;&u96FW)i1aXIYfMR z40ffp@yRGWvNZOe#hIm^cX#yiaLJx!0Pj|8^zlAIq;qul>`b;_py2wfIXW-RC$DMm zou_fHnUL$4?{G<;KZu9^M(bd=iEP;@_+4M;H_mSdez41Os&Kk5)py&I6w{?YzFJj? za8`t8y|p(X(>$eqdy7+B7kVUZ=D+3#Utsup7w<>wDs6y@jP6w?Y3dWeO7M0&HE4Oa zN|~47ykkJC1S>e8f2mH2IB48S7S<>d`QjXBe^{1P%SkIkO#(4LRceTK zJ$z)X0z1@oy8_8qCv6CBwAiHhq+1ABpV}ngjs0@u(b6}yKQ-rcsTC2Y#?(_Om(v+$ z-lJm(u9CG8p+d;h_U{y+0f>l7sLVAcgwIgNDMz)}QAx0k)jCh15nW=c%Q;q{yQ3@e zfZu0wdg#%sJpO>jh4z$#qHA=fB(19et!8CFGNzH1S>_WWW^QDv*tF_uS7uHw78h5M zt_fEn-~ozkeKZH`DDcf=yPbUJVqhw`dVfCFe4d)|Z)R7)`w@7OAh_JjuO!r(*XpJX zjDUHp8lkj6s0mi9=DbpSm{mOf;TGW^q~!mEwqKZwO^=-;Znwkcc||#I`cckLWBRMt zBQ3!&e|z^0&p*-(r5`HBdl7%gJvLTW9Ptlr(gCpT>MKc2v{v)F%)| z;ev^?$!=qr+Lj*JOzQSM|0j1M9QUyfe5M8Cn=G`n&c&DC@yv=(Y9n^cRlLgkVc^6vB$bKTC8yrWk{YgXl3c-Jo*cP@TzWGc(Gj9y z**cZxZ#jD1Z-d;yJsukGvSTW104aFp`rgr0t^DnN>RXXF&i=XP#>`HH1xV>CMj zS!#IP1w2T0i-PVK+yz&U=h+tl45)2<#FCd-8lQdLHa=#_OQ>}zm*EXsUPpr;iV$TK z)MYG`OSEz_X$Qu+y5~#hRlot{A|A%{1$fW3`@3Ex4+NYS`0l7B7 zy?HR9Kb|0K;AP<8JP;-w(cLKq3K*uG{qDQz`!qqMNzgSgeyL;0hZk7%^5N)^PJ`6b z^3!LV_Icit;Q>ENfu{VR<$DD?fMO;O*5s+h>t1e)O7AF7^|UT8`po)GjC}Kz-+$Ca zn@-g!YgkAg)g^D2{5KZsoznC_A*P$Yo-Ltb>XnUecCO0lH9py5wemUyLc;m}!wKX3 zXg-K?1b)tvj4Swuir<^DFy~kM?bLTN{Qk>B(^=vxSq+>c3l3SS0DP9@zT$6iVAy5@ zPCuVQ0#cfOA$5O^!eZe_$nM|pFocYmvsPGknwJE*FkRbyAiepLPThBAeRyPL zH(WK6YogrMeZ%oDv@)@Y)GOC;(6as3#+-frrUzUTG;vP% zO0TH&Vy0MNxR1pg9N`QR&*nO%TN`;oyR#!$xuluLm;F+uF^`1A>1_U}Mye-h9qxOZ z9aznnC2!N7OU)b-^_f+K;?weW+#5=8Z&VYWHX6XEUN8%D#N(mY#yp;l#$=@heQ$rS z`ocQyUxU;ouLcf8IU$3_5uc%afEM|TP$h^lsgN{8LZvb@Im2>~-j7K-ejQq229RBE zExQVi!wDf#75u(s`L_ewM=Ia{=2gl{(!`l}e1rHKxsz%9L=yIW|5twL+DP*>kwgYS zX3zipmQFjk#H|v`ie+AaaqC~v3ez}x>QB&2S=ptxeX253ETj6n@ams$esWwAMq=*o z2Jwlu22yjZ^Gint$zmgv21D4;`S&hYk$4**&gdz`i6O0^^vlkH#pa-%XW(iR(%JJ) zgT|i~m=PYviz69Vz6MnM`;SXpR3fX>@$LDnXLE3Z+T-6o58IL;|D<8D_Ri50O=7`5 zS)Ad|5&Tb93xA0+{ZHBhcRUY;^tT~*7S;}a%dy(^Yp+-8P+w_+4pc-P$C)ee5;#%& zY$r+{!rL}(hT#ZHq^KS2gjXr-*b@GvC5e)SO;LEOg(ip@Dz0|m#wt087*23Vaok{hCVZ3^opBymzr*fAnHe}$JY8g)QcQxI#LI)(3l#R;sNGztZH4e=CmVjmrp8U5T zxZbJYUegf{crNn$!TOp*^NS}BcFuKyGszl2NS zlm;_p$`Yb5yq>jBeCAl~H1giylQybY$G)*lfg1GS$*-^Xx*M4JIun3+3coknqzNn!_JIN}Bk5RkkcwX@9ba4avM5s(i zKo0GG;0{vI(DiWSY+m58Bj#|PXM$Ho*RP!n*t6w?G>@BZY}0}6uqnWzB<2QoD+i&{ zTN@uu_w>-rsR(>K`Ip%aLNU$9qEi~G2O4L%j#)^#u5iSe;UksPLvP?nUv{uz875i@ znD$o3wP;Gk*I=ODoK7p_*Ab#0 z?8P+i@`_n1!4cO-7Q)x146FpUxoW|QXW<{6Vmq3dXCPv5Jq*oUSshp{5K<1R zta|cw+%<`iq6D^EoILe(8uZa0Y5KO zFEw-fU|pU|4!MtByk=E~COU(0X9zbQIs9OrIt9zr_y@(is6VNBmK~bELGym+Gkbm- z?DOgN7`-*{UVpwCCt#-61>jCLH>7{+TvY7asrbja$2eq$n1OjXBE?Pq*f_0DHj5Vo_-JZUQ!gzB-Es&O zL#T{d{uj+Yz)BO@QooN?dlKH+e&6?cO7Q;be)D9T%>p752ypZ%1IIZW{H@^C5tic` z*hHi?+(U{Z3zbhMOaNjbQv*bq#z|X(UJ|7HCs@>teSsSbchW9eJYGev^72GTWNqhJ zK(+oV7jxDUg7S(%7)UgjE8_(vgEoTs3G)J0NG@YXJsb0KvQ0iNWvN-(=Lfjg#@5Tg zDC4WAWVQ8m>&41@Ys{z((3cI+M+23zV0mXkkXyMy11s_l;mv^3q^3^7ECx~CI>3=LO{JDX2fSB z1$RN;%?Qt)IzPpHX!}l^Nb+bj2z@(ez^MqUdVABkgopkjLE!vW5``-)RV-Dp<)h_O zkaDnJnh;;r;(-b!{fApn7W=PcXmSb({ai84?<^!}dVu&c@4c^|<4zKE-SvIT0ber{ zS`3NX<|(L$ISK`=NcEKdps(iW&(e(zPP4UT-(M^+Ah)DQDlxA+fL-31%7F?_w9Exh z&MHz_gHL6l%M0)CVd@dCs%Yau>Zp4PZei-MDDnCmk(`W9>6fdGMTh@=m*v;H94SIK znZ61U4deE(hXv9mZkj6bMwU;={en+kkbwHCPsG*U*vs(v;8Y6Vc4i%j^<`BGD%Y64 zc&{}q1(l77R9e3FsLp7meD^saIn|1%b&6^sZ^dAW_d5s-RGIJ!jWj8aisBhR;vdk2+l#-Os7Tbsqed#mgPK)QoTW zO+QHcL@{&#pmPagVLBx2Xf5$lL0<6A=JrmIe|ePh_~=zngW9ntv2 zzyr;C1M{JGWCQkTZye>D>S}vUgP_wK_c8Y&h9F#wf5movTd5v@_ULI0Fh@ZvG5vo7 ztbnN;r{YANhb4`eT|%xS_RP-@Y#C(D1J!fmV6yVyPSiM9%_%Ye7v9`2Zjrt(haA3JWl@`5-!n> zvbB#tsc#Ta-mccH{7(qUH2aF`4=0emrBj^h4qayZC*~-2EnaIH&`1^&cj>x(3e?*t=M1D1r+y*X4({-bj zH4vZW!2#(KdI**OgVB4yP;rm(&1mWVL@|`ICbZWU9?+$lFUmSM==nG$uWNpmYYl{D8;SMvF`rsM^-ScA*G{?OS0% z$6RK^ynE?Tjanvr)=;y(M;%zLU6~7Toyva(&8Keu*gc z%89wGI448koZ|0c@M1U-(j&(4G5;7fLVa?4TrE$P)>dEU@{dab5vX4wtqrY=o^9;< zHb#Yck!!QnW|oH()?3OkB|P?xVOhRXBvoyYnJ|eanS_(tYEVm!wp6e59ZMU(Q}}7G z_{*=e{mv&Mq`^gPNmWAC3%3FQ<22w|7qK4UW7{*t=wt-kw?k z`ytKw#L!x~5@)W>Z=8M>ginT2zWr|C$p`;l#NJ6uZ%;e@3F)#szxXseahmEsgnF#} zda$rvq_nmB1DFP376?V@m{aKh)KF_#VLH_%4rq70zD$s#RV^r zlU!}MgalKJo*Kb&4%D3M^L$ykHLxaqp6{+{h}#v}pt`CJ22nj{oI!&z^fi`7F{=~Y zt_r9nZRsIZkyaM9visqeq*&i0gjdN6VLnGSO(QB1Vy^m=j=gi5kAXX?Jm~u9JpcNN zkTGFv`Og^PCavU($#J8lx2!Ms*?HRJCjrEit@F~hfeEC#*dL5%zl$!W{B%(1#(!QJ zmik&2_-|6(UEWsPE%8eAE887+9wv=^TR%V5XLSF}wfN_c)|OaB8SXLBRtm)*?j~h+ zHh<;xgO`piZ9Tan6XcdB%udX%ZH?VVIiI#*P)FJ>T2j~wu!(ilCx-9SCTQa7b?!-n z3xc||C+W1zDpk&(f!s0a>_sJb?GAt7l&UKK>|eTMONwR%nQRFp>rHtpFBv^WqnSC= zRJ^MZpdHg_$m0)aHkM>n`<;jk7^cCRW65;EX)9jRGZ!OgpdBgvUuigRR8IIvaq1P`a>ks z;!O$eq`wvXU3eLJXhY~eRw^``_jiKgwu4dBkF?akluq0GMFLJ&#kQC0x(tSC`)~ zC_($OzvX#@rFXt9%0GL3J2?g8^ep25k4ujkZ&eA+QqD60^~>&&x?C-p2Zq+Dki4bF zf=Dfd+YSbIG&CiMDaXQ8AK64mllp-F*34%wvT6*&80w7+J9jKNoeDTQVm?`HJ4C)M z6i)wi`x9ZHLSfrC>L1RfW-*$#1C9QKvOt7@lML*eGM= zU25t9Dkl`mc`D(?mRfnm#M!19uoc) z=WO3duB$-A(Fix$`sbPEw)8ZF;)W&i$*8CVaUtecyy@mJ>=n?!jSZ{Z9NDfKP+XZXN_5BSV_3h9JE@7(3-zou1UQd>TAq-e2sH zZr?hQdS#oyo%pJI=HeOXW<}q5i+4tPs@zOUzt&)5%-W-vrZf7~4prpncU=gsGZqqnV-L$Nlg2Zk=!HGF$%DsYu z?yjg)hff`EPYGrC8FxevxJejeIBB@SS$D^2@&Njf6&L|8hI%>m!)=38MC<^`#?>H1`VBvYqf}zn~MvgoTQTt{dts ztKc$B3c^cYXW`g2oXp>6{>^%J>NV`m25#t{X5*%;aC9zr(_0-~zL}@bi z6fW%3U&gH3;a@RKJSPKPCAK|SS_unHJoYl`)3gp(ZF=uBrv364NK~y*CW96-$Mcz~ z_+W`P^w+wj&vrO+V6pL!Pig6@Jyo#{4a)Ya+DMY*;@O7z41@tE$Bx>4TveX}Y z4*7c60YDq&2xXuWagrc^8<--8ZF5N9^wsbmM#9euFFX$3o1@}iFMZ|I$IEFA8opa? zPu_9`H%}v>KZTt^0o~{>SYw=S1?%!7yKy{>>jhg9!gr{Qc}#;9h;dSVi%PEiyR)2* zr*B!eD@ngb7Y}AIl?p-)?2`7mqU9}){*(T@cHwMqV@A}w?Y_DVtjo>&b#S`q*MRCB z;$rSk@S;Lq3@*~Mxg2liXX32Ni3P=u!9+{E2+W7u=;}2pW;n@;6V(shrZdD+7qila z$;B3FbGZ6kc}Fi(8Lyrz1dcPg)=2_q4xK#SzstE<5PyLw(@2*N<%t!%KFzUY7G~xG zMk+5T54AISfW|$YDx-Uqg@ycF=Z!w3#iyd;W;zOqk!G@F+;*gF#b3 z-BbFaG+2MnvOeUXwqn5e9|JE#9og1FtcJB8u^DSbxr1&sCS7#7kd=Ds%OYg}vxCh6 zHTwm3mUY=*q=Qha4HB?}y)KZ|dLo9Vixe}02v6g1lHo)XcV}y16)6(2mKXyGh;+6{ zb0enm%c5ovvxQPPBc9o3-78}b7O2TwoG2saXGfPw8iW{EczxKQgHOa{q;uTx2Cf=Y za>1B1+bplKcO7@Z4}#UF?*H)l^6&fl!)>X=&+Q@bm`sfR^Ha_(ZX4Tdzw*$1)hR@M zJRSWBDxT^IyeDK4cSbt=3}5m}9|iVhGOe?N*N8^8NRzD*AU@NtG2kb^dY*)DuazM~EJ`#@kO=O+t=escz#tg7FV&J;O zVgrYu_boDVy2M0Kq17KjX$8@1uW9ky#*187esSfEc})uMythskFM*K5)I+xGuimv- z?Re@huj5-A(@*=1GrPo4xYS*%T6Lt+SkM8Wn&+B2*gWzMC3CUh@lV@$$Ac+vd$Eo( zLBu3WIH&la3SHL~m(lf-_M_9lcsexRX)<-%@_QTLU9&s?-UFYb<|!i3y)+JY$+X&a zs*uCA0S@w$Ml!o5oyOCXm_h-(<*;y;GFDl=S$`AZ3CI>sdWsc`H%NZ=L_}BIC@Oj9 z-@I_1wt2)Sn_Po3xCjSMGundf!bxOb82k^^WCcc3)no-@K>0 z@Yz4&%h4~6#T{q&E~ z@Lg)q7G*_3cdvNedPjGSN;CeM`qs{ga7JoWy-a@3;TM+w#HXsFBD-FvdS=ek&SZ%e zgi#X4jC^+Fl zVlt>oix^iX)GoG19jB^FMF>G2#;HLbHQr9}KpD4lJ&%HCHldCZRC85SuN$eE+v}-8 z6t@flLwn%C`&8^CUI~bskHC6P7IJ#;4%`w*yax}Iqi!yw!<7GU87 zVvDSfa=6fsKbw>_8=@Ie=z!22Tv_54VgwwUB!P756ANi2PZKXUT!hP}67ma@J|krb zCVTBtLY1n->lfDG8Y|h{=ykM$sqQT^)Wh@nsu-F*+uP?DpqP@(Vl;0$gnQ~V?bS6e z%Fe;iam|XwIfDM~2-UB+h9hjuNGPOF*(5+rw^3oGgkM;!LbX@Sv+s&`HA>mUmV5l@ z%Ak&Sraa}29en9hyk&+tnu5xFuazou~gALQU)NW7;z12(qUTnoX4^SGHCmPbwXA{$sQ&ba{_bE$3*9)_y zcB9l;q9(dSOdGxIREKMoS^lo!D;c~zt!lgdIU9_{z7>6CYp!Jq=Wz1I0T;qs*8Jy~ z<6GZLvOa&j4;LF&ymb}Rdz9Q^GT?u*_wL8W%5U43J$ARRNh1F|0dD-lbCTnCvTXj1 zXBD$u35|(7e^{?V^~de}qm@~z?;qq!haAR|a1p1RnLb3wJLiaXb|va%Yc+C=5k2Jl z5<~Jue(Wr}Re7;pOq6v7-v+GDh^SC%7s995-}=tkX-9qCv7d?{MKls6n?=u5ftJLC ztZHBjUaRE85hQdk!r5AC)pxK)kqQd9q>yMR(jaye{8*IJ)LJPEv2PDQZ4J86oaP0L zz}zEbJqw|!MFu6Iw%rQOu6*bVON@w4@ddafdS+;_cuX@xl1*VrhbOY`nBTj-FOg)=n?hP8z0*uQSn!#U_(y zPYg;RDGxtHvvtLymyu>T^WG})k>4Z8UU1w-LmdHLWxGtnZ z9;hzebSo}_rgH9NIk*96D+rg{OC0)(_`GP4Tsk*-z?=>%VxMgyXai}ZWV_0FE&Eq` zur{h0Y=mu6B0-K~=HT5E8U5~`T^&p=g$Wu0l-oDtm|n$-e$7smF=VR+vdrNvGq*dJ z7hW?pdw;ECvMaukYv7^p^C4rmvXzdV$tK<%*jQp(C7qwj1#5!GHF%8mNODRE5swQ) z=uMtlg7zx1UEDwiwYb5m=^e_bG`8~{99gmO$W)x#4aAb8)#5PIj6@ts1o#mS@r4?l zpsf=a$r7If4%#yzU<#R1T={W2vZ?&V661cfSA1*razuysd46@PSz9T6gE#_uyN`_0 zPxAPLF&03q0Z!-Jx9+itO+DQOru)#26l!}k&Me&1=H%lT$z z_HpUZkW%E1_?Xu8#9>EqZIPj!y^dAUL%}SQyK#-YzWwj79&SF6ED|y`TKgNm7?_bN zX)j_DqKaj-HFq9TRO>9q#2UVOBL#c+rR}tuDQv|sxOmaOxlodP6nbLfJ*n9GFcq+YP_-&R9}naR8pNDrWsnaR5!DCKnP6Rr6t|~aL(pL2 zmS^8OKF!&uh%|^>(#o{2lap0_ATRf6t?rQ~_S;^Q`XYs5Q>%?jB;P6gOCuLNWF2iU zpiOu<%0Nl`R9k%sP=Jw<{-ltgk|Rt(1M_u6Tu*Qbs1dR*g;%2Zh-)>LPKeh!s}c!` z2PaJ}nR&$7QEp+>4zq{H%va@qVManw9;-&ox4O^YLc4ORX2DC#ft0qgfSP+|s(r^F z-D?T4eI7Vp{&IC+Y~=-{!?oH1{F*?5<4vn&+wEA~gYEqm1a5g&t?vVF z@qU&P;BDRgZ)djM*?f#pce5x(7oX;L^jcP3%pB;G7>N@@rm&E7#*)&pB(Dx7?V<}1TWpv9}+hBC+MahjZGtE@3%U>PN ztn=)`rXWmUgGP92Oqlg9MmO0@1}@kDE7)Z(jK~z(;vo<-uL;pj&v9yNj^bt+7cNSZ zLk?v58Ch{eKtRBJuxF3qbBYbPV?;%AP519>$X3N`NEI1_BCZ2Z=A$!gm7A^=`)yj+ z3#`P!$c&#KpdTz%c?z;}W6~9}t9JLX@sQ_YiO=g+8HW-EQvz>;u&31iKNC!gcxzH?= z#eI8r7xOw1;%aSxfsvvmv};P-o6@)hp zX~P?xW};5CI*OTrT6XP$HCk3Vt4)@)q#Z9A;>iQe5e-l^K~uX8SF`0YCzlLy1%1>^ zA>u(hFDYC2frCYpuwsJeeKbNqZK3H}&{prb4^|bVFiemxc>6ZsdPEbiNkxiv5heOSD&(;*5&sekc^a#F-;_Abvw@$#cms6YHw0`U zyoqz6k~Tcu)27q^CnOw9+cb0w|Cbx=@lWC+;IG$3**ae_&_Mv2Kg{<$dsS3Lqw+} zH~oyX6gQo_-16N}X&$E8s-iyICs@vuKBe$5wqo;gvoY%lMfhOq-im;hzAdRfz?K?yD z&brmGsHxC(v*-+vWJg{%n}MHB+a$&bH4yFNKD)#zj_FGf&#&2ogqpdbz@zYw^!#|a zdMk_hTrAS@55Mt#)81`3X83!XEkP$?wMlNn52xn3<|!dTc1%OGtgO~+&a51ASxt`jfZ@h`K z_T569ulzPW(8wzJkkm_>X^Q(O+3}B$a%m52@v=JpW17zqwp%N&M;8CE2P$?A=lF*^ zoLYSeb=}iJiS41kT-}AJGKLFT<1at-BQ5EkvL_TK!^8!(0S!lx$H7POl!eqxcX2Ps zh zhT9j2Shbn2Zr(O%PhFx%qM;&%u5UFDG!g(j&B%=GgHJ)&x5Nqg24LLwUh1Nhjnj6p z_t3ff%t-%{20ATesXgyq?a`rMDzB+2cn^k6pa2VH_|-N_R7ehos4enl$R##s^Z2{9zHP`a~03Ng(@lz8)YMBL#I z^#?FNqbH;D^3c<|CKdK7Wu92f?mYh_8Z&U`?|n+HnJdtO(6%Ks5C5Rx|J_`^WC+WV zWhvF`F;V4f+Ds=s0kxMvI9X>)hz97UpHa`DTSFl5kv(*pvv>i;wt0_s<5!12z?-_WMAKiZkJv^Mh-fsorFHTjNUY1i$fu>S2DP-a^W7_ZolOCIZL{i?0hYJ0F`uBA`lXuL@9mj( zJZ{8%>Jx~&RN)gCH2@P_FULk$g3sw(Z0`bY4%1+?s`{cvFfln4*pumP;wMW8vsld! zR!$Zof?U?EOihTDVdUEx)DNl9a?P!P@k!%u2zc|^GUfwfJwZ859XfoCO!<3KQu)X| zPRw;YwHI*_ROVYfscA{;M;U7V{<&>m-fTF>(zltnJ}TVY1j(8A6cKq_ITd+Une-R) zn6jgMoCI9O9DKa4I1Qcp(Q88#t~>-||E8xAjbMdRKj~Ox+bFq8og9&3be`59Np)g+ zS-}0x-mB{Tpo4e$^wGq2mtWM>kwfq3qDn5cjvgYoT06?BeNI9Fz6CM^2=;ST-gqBI|8YLIb70Sc&?8^T0n zX)1(d92cjc#4jaY;$Md*z-DeyCJ`?9VR{_p@#HB&urDG~Mh~_Mf#Q_q>)$rvtvGR! zX?duwCe|To&V_a*i;uF9>RSi079k(oY8u<%`lZA&9SLRn~!i>GbAKUR3yAys9&eKjb2GjR9yZ{HLU*3p``dFC&8$b4HwJ*W0#$ZszRU&ISQ z^_r>oa-rcz^GW2cLW6PuMbNwkVkA2o$WGmt8yDQ2`h(RmT~l3rDOk-_&h2;ha~u0W z!Nm^7kUf>Clb1L5MPxl~P!ZKRYHkfEvWJh!qeh|#w-+Iv>!r$x}HyKME6+|da(zBqQoT};K_WMv^hUW=@GA#haUFNP@y3v4tnPuBJYsH?py9bKUM&AF z(EQKOh)*(3%f*nRg$BBi|6-hd-QpP<8BJKe7(2nIC1 zCM4qGphqN8xVoiK2-9*?eP8(tB<&YQM*jQ^WyX^2+EjV8b**Q^9?+UWA1Jq0xp3W6 z19Q`k>#Wk%<>1WJHuBTb%YPT?NS?n&@B%JWytSZqQV6Adkgd7mV>0ub@HlOk&p1xC zgX<7IPR31}SO|y-k{K%tDDA)PC#~uobRT5=)ADLkXdUeedk>OMZttMwvTcqK4_Nrb zv0)tHG#C5`b;n*-yprV#yx<63#c$7cfQwVmkY=TD{JTEF;f!`V<3wxtXQX15UpC!= z=6Ty}+XcA!hzF%(NGL%LphG{;uMxS97h)e(d;E`&-x05IO6$Xvn<;Mna3lS3YWQ+V zEK{#q#+~S63DoK%H&BXcOI>S3q-bpikiaov?)uAUfIdxM^Z~3wL}^3+CovUaZFR*0 z{LNk0%9rcdJJq%jnu)9Rag*||caY&R4!9}R?=+QYTl#JhVir)2ktS5h{CFK(#!+tD z`FCwgAhHRqMq^RwoDzKAjiN1U3cc~qq0);Z^wbebOc@EVjiaW4eU+XfALTI*JFfNJ zZT(OBUkF4yXtJhy4QNaDj_8rw)L1jW7g#vV1ywqj;D3S=ESHONSzcc}VkDPU7GufK zooY3vW47Tjb}apRqJmk(CMNIi)$yYSSbLt&iHs|=-lyi;@WK=5Tsg*jL? zk!|X_TBq`dcdsh((33^e6=DYy)ydUtjkN#+7IC$oG&*IfEE-1*Ou>joRN9&bCxz@< zwCgl1nw@~Uv5#qvFZi>O>U0BM?l&mcG{rEVtt9B|{OT>owyt>M&2NI9NFZjwX5vg7 zKm&*4L`*Gdra$Ni;0P_al|_)9J+Ndf^>JrunMXLWmV}mxS-_VnCnBGEXthq=zNJbm z(}fF*m!eT|UXYsVFoMrGKkl+$89Q&5iE;V?Ji=a%4Z)^7xRJH$`=`%JF$Z<#h6iOO zwMG(SCz9Vno=Cq)z_yeho}l{0a6v6f24;`ocVw40IcCsfC9hdw7c4gH_V;A|t5f}O zR>ShH^;fyPDO^zW(wk(1drjJu64OEObil`Cr>~w`l%|7;G?ORPfGlE6S_po5P3Lx2 z%z)vX2meAMaqLhE|K@Pv8dcvWqE;o>{Z3X(F{~2MTo6^QxWV#r;FG?91~yF=TUh=q z@SUCwHi18VF|)foP8>=qjoRxtP?w)Lvoq;9<4=4YfAu~lkonW*>IJS+O#|v8+w&wa zVayvdK3kb&3tc}F3C3x%;~Xt0aH#w$7c@P;)27 z!T!t($>_%E*1s*3zM^RX;=H6OkcCnb=G*ygZ`k_l`^`~p#5!-V)G95sQhv4oiJ^(J z5f4~SC7?e%LT39s;++@U`QG)tV609X{ODE&?9+W^-GYs~?XA+%Cuq4HeMH*Vwz zoi?CO;Rwf3R*6FTBBec``L}yS^(=H6(ec%$r*7%|7obM>6hc+lOQkK=BUOtw zz|rMPe(S3Io=82f%Kr&zC$IZn#8m_}JnnZ>2+yU5-(x2}jUZWqT|7^iRjqA$BA-3T z=o7Czg1DP^HW1nV-V!tc>TUAl6A`eJT~$`Ife*q%@B7^b;=Y%3Cj}KvEUnXol3KZ} zCcT+vWkZEYlRI&=&x$m&sFbtvAa>Kfjdx(zZ(NtF@ieY{`2wtL%V*!=1lywz6Fm8N z_&71SoPOJOE8sQk)7jhUI`pb7GRuSMS6A5@_y&0C@e!YCyC{bnEsJ>gkaomV{$hJ9 zEXhF3$jrW7M6&gfW_m|0rUooZQogOVI&(|6_9+^z=m*0^>G;Jmy`K6WVaF`AM#WN{ z0&>yDtIa9y5e3r_@$M6VQSI5Rc*AjUa^vkP>w1XBHDo5ZUV0^h*|qY6nLxg0jHg-7 zE4QS_^g#|_i&vaAeVnB{g*Wc~xEX%mMN{a!Z)iL{?uS(Z#j3oi^}+Qfp(ic|cX$I9 z-DP>r@CD@P?b&mZ?OhjQ^YfvZoyN0sdSKpms9fBTjc7YzopRkhQ_5mO4)?hoW%lyh z7P`?KublD}Ak}5aPm2>SbwVumnFx;&au!4f<6NV&+U>Z;k}3Xi$|*+})g$Bw(KzJ$ z)I1zzeb9`^Kl!gwQZT9V4?iA?r*ddsIqtY|?SaN;;$@RA~48 z{XhR3ch1c@=Y8Iv*Yo*$Jk;M1^bxhec}OA-RL0TB4DZ%fUs+3+_F|T$q6gVkbOjj-`HqdYB&|Ne&!z+xEXm#EcmB0&7?sXUyPXa$5>9t4y{^TZ{#*xt&B5 zYu&ky8cA>LaJNj6jx6RJ#|$JsZ7vlRGRr;QD1z90HMs2%1juv4W#Ef<`y3(&G2wp-X!r9ptA2~0yJM_bHRpv6dGVb`7Jw1{?s1n2lTQ)lrty9S1Um9S! zf!^z3P2*~k6lYalPh@{5YLcL0s~wNOP>aSKS6@xAb`-dC#*&(x;HXkfGZW+w+}sQ| zK!t0sz@0|9TWlnMO-ffr*2Q_Ux`orwrPD4CR}8qu`!>3ryF}qATiwmC?qiEIeTJ3p zuH$E+*gRYe+=A`7>vA&=O+BjPP6~xYop`B%yb-Ft=~?TKTlc`rejfR6O1TbJKLOwO zHA`@QKlfNP;Y7=O>J;iBZ{*bxF?_J))3O9zTGf*s_49Fb_4l!h3WQGu^j>4K43GIP zs5OG#APu?pX|UwseV)@p5c2ah!LIQH7y9WnQlTquYq+qI{IC2q$&9dl7iEPKfOd>* zbem~?#I5EO$6d7eWQix3$l*gu4RDoxcQa@w`str=@94$%Z8yJK*WeXaQ2-)uy!~7} zR04DqMTk7CyB#q$>J%vZ6~*cBf|!%nFU8jo=xHfQtrD!XB`I+;YvVk7SbAC^uj)hN zyJbY@O~6v%GsR8E@kj`I;eIb@VcQvqi9^TsEItLs^QVr7YcR`&EWny?Q3b-aAGMw3d>ag5jLmMcy|Px@SpsI7m~;Z~Z88Inx}_NT&4k<=EI zEB>^1j~~l+00Q9SE=WR8yqVXNH`{SDje1#r*W1^d(lUJ{B7sf|iQwiapBN=n*k-=1 zeJ=1N_L=bdKOFH+&OU5g;Q3{+=PBi^s@JHJyVUi#xL5Zz482+ms)!F|LPYU4OlqU{ zwTQ-PMOdCJU>FLEcnRWG=(C8F-pRuDiac*lyF0FQ59I(_pYMB+F^$|uDQ|!+U(sZ1 z4gqIn#xz(l;Um^be_HE`8jFJxPKcnKpraqE$+BvJI`gTw{qn@p z%E29XMVVAq{K-`5GGve!z(EQQRt}JdW=*~SF3#}l3B5C*wG{0meXP#jAGgvufet><- z|IN&Fa|#jHhPrSgwa&xFgMXvrhV?o zM{>Lg>T2pq^PB$Y*p-S(!Ka}@bFExGFFCa$ z{UR+X-FDHVG0+iLQ&fJi3aYKY(%Y6@cG8sft}V`CP&!$tIF~eSP|D00<*Q}{zAMDL zY+@9%jinn^vu8xi-(}k&R1sWlk9(?6h9U+XIPN4W^tsDro-opi!%(S>3wbgNS)Ap0 zA%!aGsU@Ro)NS{o3X}JmD2eIP>vx%B1)y_G(SYmx)ty)XYkXH#VSWCh5g$O*!bViu zvhw#p&48Hj-6QS+ta#Hy)$R`b$5G6P4uC~g6gHu)RI$P>G|akikrl)oVkwQ+s#VD6 z%W$5uV@$)j@=wj_`6n=~n)9r$zH`m&nbeT&IBO_S&SafaO5 zq3n+L(NovEVc&qX3vkg0#GC>3HGoD;umr9Hxb(5#XJG?r%tXp%@WBU`5R{C|ZOt*eh+#0eY1eIQwnq{~B=s2S77VMXGF)lhg;EEHt^4IemtO8kuHA&s@^ z5z406Fi^I7E-3J{_9yrFE0mxZC6e|8@VSR9`n@omyERCfmiqsEv+KC7Q`~X|LMgLK z3@l|#5@B!{2g4}ENMIZPs|&Z}4kC(Zr-?XgHLbWB%Ma?a*am%Qf$Uheo|SBXLd3Z0 zO=c1-M@#gl4SoTnRK6-PS*Da^m|Q&G(k33S7ykz8!lf=Fdu*3sBvT+M+34@8e*9+D zI{NwGR;eW3OE%6@bj$*JE;*6Hs}M#M6@!UzU!F$ab?Je!D9YR;`_wk<-Tv#)tNX?g{&LK z>?Ys%`tDj6^%k7nR^pk!SA!hes9Ow^SP1)(R&ZsH(IhA(nAu3l1_^HZdvHltX&DFQ z300Q6$Y&Cx$D0=UGBK$4qDkQfoftQ6(Rr#5E+3T7CXK9s$Wsr`jKXf}9f3*N(|iVj z)-shunK(e33{Gspe5W7ycH}=)>S}|KE#2^zx(JRB#1v{+)~HjYEb0=&&UItgvPAl= zE_DeS3lS`JXGc`J%)XxzOc;E-g;)harSxFD?_4{AjK(>w176ULM z)8Xy)$@=?RFKCjj68_Am2h^#(Rmvty~jr=hD8AHU$yv88z$U6g*HHeZ!bEPg(t&(IIEcdFO)P}uxIF5iQ$ z=Pk}<_ghf6r1Kzj@#RMEJo)m(=xYT>_H<50qhngw}+vulO=yx$yNefiZ805eu3& z4k27hO}fULlG~+D(V4atn0BJTICvRS-$}4JcqUudK>Q>=x}UlfAynLy%A&^O9`mWY zTLHn3nk1#z$;6hfpfUls5hCazSyP_(;?ctha0VoV9E zH`yUtyQ*{gj70DlVQ&%L^t+XsO;$inV_WrVYQ!tC#SF#^r{QvTh3M+!Ymz~s8)(+M5O-`;sp$DnfFzeWuiW#V zp0?)27E^`Q!_GU^oeb#+cCogFUL&SoqMO# zKFfEcS=EHy&?BjjneV;;S>vh;k5d#DmC%ap|r-;&fB2DQ_ zZrU#)cb<`q7lA0Jy8h-gnFgL>vy|?cP>n$6TU5V5S}noe&!!ze!diXeB{4jlPAa3= zn13U6cZ>SSZPSjksOV{Do8#&X87rFM9~1|#2JaYFljsJx=ZqUQoSw&@u^hl(=Blty z^)NPHC@SyLD@(l-V9%^qHZZhe7g6Qt6q!%iQoiwA-Tqf>XyD`+Tyr@Q*3XDcb-!yk zxb@`w-cnt0@rbVf%jD<*2SyxrtN5{|1aYU%>z>UWu+6e|X#aG;cZR2%fYgq_1HU3mC@Il z)by_~^-ETk35(9D(3Ap`6H7r=5PowMKr;`HEMyo90^^Q#bh{BKgK#Tf`ugWXviy@* z0pf`wSq=cu;5W0~YL-RUgX9opKtNxtoMZ>ot2-bACZJ=T`K;n9S&xt#*lJ(c@FXW~ zCEKb*U8K~dBMDQ|K^8PU<-b2fN}`|SxE>p^Ej75 z3&>D{3 z3?td&Eg^E-wp9THoH^Pk2_}N~@tRo2$UMczSIKwFK1(CW58h4=UaJy?+skn2x^5rV z@@RV!Lnyf@9bCT2_eS03(Jzf0;jk_47`P{n(6fB6&e5-OR=!+-*A4b%IKQwf({j42 zFe2ENM#eNjKUsj$;cxn}OEL1dA>=wHrzGR2`qo*s9Tm-&`CldyMzss?KmLs|ga8 z*0~0qs0Wy`>YEZK@Qg$11aTHXZRaRJj6rl|i!$cOF?`=F0Y7Ynij|?&ayr2s-@oc; zDtl3pksY@B@9)Bs+u5pZ4^`xGT=l8SsnTQaKLNntRMtZ2)Q{%Yr1%ntRSaMGTLYn| zye^fE?j_Dy8K|Kpx^J(6k4?Hoq}knt?B*@9OHh+tf~OZrU-di*23(j3{Qi(Gg%w9a zsnm{xJq)H%TIPOay^ z6Uzv>=$(sZTnfPG+eyX)6O)(5tjhzf4p{Qtn)%hYOB&paKm+oqGWhCL4Lm_h>l*!X z&nSM@_i7T&6F3gag9s~s&Bjx%6`veDR>?N)$b-B@SZdlB; zD*OzWtmIbNH>mksmT1{A9NzU9`I$K(jLioDWoue7Am_Dg5lYYSa4})Hi|h#(8HX+6 zPGQ-x3VA#{mEKZHs6g|1`{*w;@`N>M2%sdRs!j0HJk-o}s+I=MfseBMA3 z_6!MU1i>w~r{M6FESGSFSFvZ_5ZqTWGM%n`>FuhYiAkRYZy5-)22)JraGVVLM+NMR z(!E`m03c(b8L`vbK7Yt^(aLh}lLn~wx_696?6EN$2(>|*f|tOJsmuyLMUJ^2NMzx5oP3XC#p?B#Z^dhW7##WR^Mxr&Jdy z>m8AsxMCyv;#aRSMbnSS_T}b>u-3eSC2}JHuHEo4Le;#PeOF~{+T)jA-DN+8$fR~=Fv0;RMW)6M$?GvSn&Z`5s;=Z?4%%`;t!8Xcd+$Sr^ z9n9Y;U;~pE6$0}e6Jqcwpj8f#0^G-;ewon25VKkg7jdFG&UJ>LN^a*ti`d^pqLib} zJwlBeQ}~RH>&yfgot9IziCYyaG6%$ok|a41d%4L|JN8`?9kWZx!nm=N=AZ91Qw-vy zyYikk8ZUN;m>Yq;jRt_fz%(>{iIU}EgPz~^^CK0pcIW*J)Kins47Z);Z!w$tL4O(w zo6d5psIlI!bll>`}0698C06Y>veE#Teu3{ zU!D0Wpk3Urg)#H1;zR!YzxZDPxl)_2weR_ko3!FP9=CrCge)cKd(DszB8^^dw5Tmx zZW!c+$KS4>i*xVlr(cYC1DyU#w0_`)6+Km~?!Jw&Ggr26h`UvD>KPi+H=$DbL17sAKv;_B8xZ*>K#&;MAZzxH= zZ^;ZT55T!8HE9G<(8ZqBfWY@S;?#Pi(x=x|85g*<@r_?{Kroe=tM-H|PQ9AG2-{P| zUdl^$&Whu?f*uI(++E_ zsRM^bbrW_`zBJZ44JD-zCFs7iz;Rh%TN-Wo~- z4)JLQNna*)GcNMlgu1rm(0V;>FBRzo9n1S;8Qfxbsn<~7W3PEe06RG~ zJAQDPl15YuruN)ZZn;?K!tQU190Y|dRCkYTRJ{tU=5f(QH+f#x`|4TZmf9Hh3drm2 z=(pxW-9S@Ifo`z%`Q!ZE=JM()*FX8OQW)BwtlRObG%*9LAp`N0Cgq4%7M?RC-ZLRB z>rRXK;fhYUXrRI54t8CAsRG1F0Gk40TF{;3MRDG7$U>;)AfaoDBm-8 zw^oQW_xEY913gH+ixJjSDg{gOqH_VAr@rMlBG1LQh_fD7KQn*5SSa%DkUinNl{U}U z$8ps7$AP=lGQQ)$ao+_8E$-(Z(A~4xF0g%iW{?bfVesI4a~#5m<45B;wB?wH9h2Sp z-(2D0>qmSQ-meaB@7v$s_p#ntySJON?~nxh`!|k=jOWLWN7n5i{-AyXd&SpT77<2L zo5Ybn?xa6K8!g=L4f6jUHR^jh4j_SlYx+5R4(%|OhISb!2>aI+-f}up#6c4;a1A2u za^TaHxbOVExUj2Nt^izCqaF@T^Sshe-}*o zEk>!V3ro+O{KJ&G_ECN-%e1uE@k!y4&CAi$;uy|-OYf?wpNRdRz zjnpDnx6~Ogjw7)8eYs=6ITe1cixGsaJ#e(Z4P78tNFZsy#_9E!Qp-d52e?ABr=40n z7Azrb8<)G-8Qfq=iUA-R=clUkGpk#xrA1~n5}Ttv6=z!>8tjgnXOqtOr#0Co_>;t{Lwv?oPr_1%L<)aCV{iti=d zBMxL4dvjryi34c@Qqj&(J$k8HrMan0cxaH9?)q0+!YJ^-w)1-<@;Sq3cjv)?w~=o> zPo=3Rc&$$Fq*4$lK#|Dph}8 zO));#-wu6R^S)PKR=S3BW)C+q?;emu8P+ZK>0q`i1`=Ey$nAsEc5}SvSi)%v=F+6N zux3$SZ~YvSSdBWXaVCkq^e(E!IsD3)bvw8{E=I+_JU21wRf(kmE@#w+cO7cda!gIw z-eCB})!=|;#HGaxxg1;60cq2U#S=it)J#=dPw)!9w^ltxJll}Qs>Tz?KjK4gq=vx8 z9ZVVq1b^+II7GPmn%uYxakW7;x`kb1A>+)dYfu=CSKkmu22rfgKczR2%VWeueHFDph2f4lk~wYCu}zPs-bP7nPv zCpCQv%Gik8chVMX36m00tHKGtN+YDNo>-&9MjCJ;iuE6s+t>0zklMk`zc)adpkqXuW2Yj8Z4{~{nxAGk#d=!YZ_-G`H?$+Ue0&bqKZ zPpqPIt9ZxxLr{| z$1U+4pUf|!M+#3q5Hw{+x}p|ovqdQe<#Hd7nuIPlCXxcB2`>y(KYt}oNI3udbYuDT zAJ%8SjuSPwEf1v6>1gf&#i#OJFUnp^fMo8ZGX6wZY_mVgA703X8Vvv1cJpy-3DH_E zBtQ5*YbuS)g|u}_cifZQ_xt_!4z>u-A=^mLa|1$OcJrws(dg#2@pSLZtn~&7oRe2IA0+t5Tt<70K=^?BahbE+5;p$VD zgA(^$(x|U%G>-d?{WGTUCcmedHvSQ}M!+RV;TQZJwXO5f3#-YXeMS5QN4*VK^0{xm_x2t)w092hh(=;H z^7FI&PCd9$#RXJVnEOe5xK4OjYvElJ{KUAA&eSp4`NmS!N)c(~fVWrk$F=6>N;XkH zPMhxsg`3z~K&*&E9Dk)Jj^>l3f@!0GMP>QSm}-?V_+;DyNlyLDt(0wK`5-OMN(w~m zn}h05$7q{=(zgmV3=7bTu$$QtZ=1@Q9cD0VcxqN`cz#igc!)spW+_?E)N_Ggz;0j4$H-1 z+j7(a$`^&IGZr zG|tjw8fEJg`fR{;kgmET$7^@VI|=sLt;?+ zC8_tlWY-Hd?rSf8x?y@@l=WYt|FrmS~$beg!__Sw?Ux<*aa!Jy0Z;Iqg{tub}PyEM5L^dnW zdSquiZo6+q)c&cE_n6_I!d-tE|3>n)%_d|6^e(10=`Ssz{PRrIihnTYoe#(^FY39k zt=(GBcTv|0+>rLhX-2DTx&6}8M@{2#spkidT6aI6=!2ezK2$B2I(^xld^`5q%k#vv zk`&d7v*9+A(z|M}+_SPzmxruIRH$)vq3vQ$+Ce{c0$acx#K}X|h6gSoYIm5On;8vi zN-gRgCR+uh`QHhs8&RnVhs|kbQhS@6pxr%0BKCTgEM974i+T?VyZJ#$CUWw2dynC1 z>|Az?kDUWJN$9w-5MkEYz+>CTFy;ahkbLjS)dsMUJUM*H z?=ZoBDdha{4O5nHtg#v~stB}+?!$-4;Oy;S3ptyjk_%6Cq)cmYy8`|?5WmKy8Hbp; zs;#;|h_%SN2v(0|P~F{Weue9>Uzwi=uUWqnQ^)H!PgHxf`%dCOxj6r8xRUJ?r9W_Q z1i$I{`UftuZhR@$`5cM8#&_=V4X2sDSz|N%cbH~dI>z?mm*Q>#wt(za`5ST z+U63TKPDQEqs~~(89>Vq>01e|j=1A!^8sXp>$N=h}6xO!L{ zEE!f=g}#4O%kc)6-vpHYf8p;50(BPfy?B0ZJ5r)e9#hy%uyU;I zfPVu>^bSpr4Zqlfrt@m}LEyNB9m3P5a(WxZ;F?6lcWS_dKBM13sei!rrQ$8{>#chAFp8HBYmv`-BIf%KK?in_3!q-)U=ARZCb@+VD>Y13_#^tpT;K&ll z@)8Q9@^KSCwrC#|0zdEe!-eG`w1(8N!cAGh0pZ#olz6NGxQ{mfDboRv9~t8Ffsz>J zc_(JRz}u6rdTLpXA9Q5E5s1sIoOmdM8v+2UDoX`3h?1yz$(>9Jiq6- zBmj60W(ulTUol&kLD>v$v5YrGrQAmjr?K1=%)^={Auqvx zQ&tSl_-`8~usso^&+Q#_^E(OE>g@OzrX!7|j3B&pkrZYJ^#-B&_pDQ_A3JC6T2u3>+l7G7ty}i< z!>~fDuGRl>h~5y)IDCfxTtNISnDO~Fc@;S$KgQmi(|vWriK3Npdgumpce8`%GF^O0 z%&FUb0#j(vvM8U^pj)+0*j8=Z<3-*bdx)RM=$4yF{=uh38dZ<*%XcSfS&&M3WW5{% zNjEuo>pe7$QSqUO^UjM6@3*>3X4Q~b9p7UMkWaq5Iz;7~(VtIp}7M&@J zIjtSp+{aC_lC^9*Y(hs&&$+bVf@P7}7(qb5^WvDG&J%aV5xrO_QawKa)0<%1Qh(-H zMm)ZA#wMDpD#lVJfS7wVfA#D|yp8PR8mk&8o4z4Kf3)%pT{S@MG4vJD)om{Q^md^k%S3csiwCKks9L35mQaGfGD>X{Y+4ym z8H=hPSC=}Z4tGG_Uug+GJ;`kN208*Uro0M66ao&mflqo0{l{_YrJ@6mlWf~-cjneA zb`!i$>!9K(h2==q<#%oaz-90qU(uQsU`@#-W4=!9(TPZF zAO4o`3x-y8BC@-G(>nbMX;GNFa!p;2Hi^%lWu?|=T+ugee`NAUX5sdigbRp*FA4## zr4poaqSEpIvX@XMEoWq!8lVQ)r0_c53*oW=S$?#x)sXo^A;H)4^;N;i;NHuZzrF;J zEB7sS9%ODxKNDsXLyYg^6qLxKmh4WY`@j`x-b*h|TL2%iV)2Ra^i$iN41}Jn^Zh;& z`X#otBZM^pN8b0;OxJY@t@FRv!c$aCENEylGiijN*r;OnR;U^{x}@RC0Wg3pBfLWE zr6GM5J4-?6WF&EI#O5{!GX_*SMm~)XFz*Eor8Fdi=3IDp5Fs0|7>3MR ziL%4~Vn<;h8`44~Owp@H366hC@Jw9lficHozccO0Lyizc!y zcM&?7deD_oWZ7XYTuK4#>CO2`1F;dztdA%(0qv>gJ4Rd4^|1;0A+N1qfp&42r0WOf z(%s5NGG#4MNyoiCo71ebxvFJ(+v0u#!J@-1YSS+`@YXTVk+s_z%~s3J;r6;HKIX!$ zVf)rk=qIrzlw013)Fp@70Ld(1qcPhcUW`gPNuh3~%kudW%H9710Yx7uZY}sM(m^08 z6Jj}vKk))H!O70h)2iIDn-Z)TCFtm8!L#F=xQP$-qtRXhBawQ$-~PZ+LgnMD!^FG1 zQo#P#yRq>mYn>oiD=bIH6SVML27@VD(f>Wa7(MSc4IiBJE;Drai+}U1%!J+IET}Wc zMenZVesA0e!Gex}Us5hk$5$GnR?eIw*s$pYovoMLC7F4tZ^ZCbgl@A<7Z^yIxT(zOkC>U325^ZmG+euY@s}4`$z@43(ZQ*_OeR;5;MW%yIgA^fFMa3vBsLE?pZOuCI>OV4szQSNL$1%G8o%_mJDBr1z?*pyE zO8R$}8^@IB4eN1en&=bsnR>W+0+Tp;iCJQJI*E8Veq!1ynWn$*K~@mAWJ>Nq9)IFb zAX;uRVeR2JKn1G&U`}()NhkYMt{0>SHQk;#pc7@H@-nqWvx1-KDbGk*(TqG7DlCTW z)T}h%7GB7+F~KK1DtKyT++3z5ThUs-rqKy(Y66m? z7!4u@d*O1{@kuHZ$}TNDk{PqZ$qmZUn@bLeHfQt>EGs;0)X>Pvlv?|(uS9VX&8#dkMPLxD?dqae5}}otvj=?RE?TCM?jg z`1x>6S1$#3SRNOw0I*c47wZ-*Qa5fl%C=Lq`uK@_>Vd2i$eifELCtxI8=(Ep+7ES& z5{h~be7eMZymujOvSfAxEeDmAKad<+ zC8OiAP&#iyd zwgja|FqMRS>030j{^73|mhyp4G;X^ytL)zc~&=j!OxMlELz8ovsx$=G(8q>ZGgs(L@#V}Cg%~$%yzpFR$N`#zKAZ?D>xtr8&LI44s|j zT2YTj^ONa%*PvNJj~d#?wWMg_smOFS%D`pAdxIN9c6l5AU(36K_EMyAlBxRZp8P|h zv{rrtn#f2hk==a6F(`cC8++lyK)`(A&u*1Oo#}lq<@;;>eK7+&b~3t zx{#J@$HKk-nRh`iI0--k4hQjTn2*kYE=jSezn&g`Jv-pt>L)gR_WlCx*OOpaN>^_D z>q`5|9n5kJ?C-d~Byq+g8|LaD11`)k3v^@|1lCvG-OzLrc^7Rhajz)|#>}u~jJ! z8FIjpv+g6Jt-SJ@h|A-<|6Y8d0uRfcv1&Z#{nhoG>ow{!hAH_hEO@O5+uL%sirwfV zm4mmuGamZ!hAHB6gJct@53Q9eKe_f;`DB$at6tCa`sKFKnNLJJLBQhLsH?;gGG9aq z1E)}Tzs&GPR1Ar_LWC#7%DuBCsZS;gmV&X!&nHir6BC9zWH-1nR$roH-zMHB>AF?H za?h2k=et;ECKDBzRK-4~U9Ii9sH}{uT`SfcOdsSyF2CwQ9Xm)F?))pG-`9d`g zQK25NxcR+_YtPX5BVMNXsV#%U`s%P*uG4%^vDz)+zb{%mqJ%>*5&5MtHVlQ;*}HF* zN#W;$g2Yl;gyG7MRsg5f07YDe*qKEI3R*1dP z5*)AX-LQ!a2cco^OQeMbp${O<<`om_o0Xpov0M6tXF1KR z3NN(HZ7g%y)n0?V+WzBfKxq#*dw8-?WUOhR93a@mHI8{W|Wjd-^)H#VqSx=HjT>5GXB*M6DI`3uo_tN;(@Jk$Wsi9ag%9V zD_EuD3C9C2d{ZI=i*Hfmhm9yi=e~y3el7Nx)R#q<-*Ms^X1lbiuQ{?C{C-dhMRB)^ z4?2m>LzLt(`sRV9m{sYtO@ewsta{4TZW99=vE*33>sYSgy9;me_cZlHE_?O}oXpoU zLbM-iAS^prf;DeDF+6S_%0aF+>kPK=+zPsRJ2`~)?Zk|=;=~r+Z{)E9Bl5T|Mh&sg zFws!7!&cgjm~c)MM#`YRkOtUQwIYjzotwaZUULnr{8fzO$CtopOClLB_0Fs;$$;T! z`(+FThuTvgHnwV=eCJf&tnrrL`%TlO3`Yx~2H(2zlx(0*i#&Bj{Xfk5HI0FV|KuhG z!rRSn#2&Wl{cw3Q_cnS;^Xb1PIyhLX5Qi=^I;JhCv(@u?|Btxetoi&c64YJ=X{;LQ z+H`wmWsS>pp-jSi-_N7_o!tL8u&;Zc@(4dz=wFRW9-@a|0I#JI`{ibjTK#37r9Qgn zp}MT!P`I;3cFvq$=-&jCI2U{Ft4Lc#i{?mddoK7dHB&=3TCk25+YN@T5zXZasr7fz z{B)P;;ohf&=F_T#kZ(1fAwL>VZVY&Zlcg+n(qxmhQ~o}Xev=F!Vh@TwHk=z`(Ko>K_Kg-j6+wQdc6t5r z=KHYxsGB3aCPv~Jo~O>h_Dd8k$DTCIPjmVv@q-o~^WI7IsQQhJZQIIzX+q9Ws_9m* z=r)@AQ00C~{AHqSKB0j8mKA_$tdk{B^wrHT*R!=0?Tpn7aJG>w!kEuBePZ=VdpVpi z>wwM8F)u|DQJc(1t9aUu)5oT!uGEUCltIJW=uE#;=E8G4ZoSK7??quMO-qSUcJrKX zhS&SDUZ<%8ISF3qmDZs;VbKVnFLGz^H}M{SG^%jhCK1SfZhph@-oD8>3LEW`lEGgI zx0jrDiq*k2B9=t@uRMqp>{js)I0CWUr%OE-j0B3FpcOj>*<+`EU7?Te>d12h`ZCpL zTzNgsq}n(bR=AI0m7BVMcL?pFu<-Z6S^JLKJVOTlB8F+`7Z3U98?c_%)f~`x!uu0d z^Tv6#GT-2?KfisW5RAb2|M4`+my4`Kp$V6V_umj6#;yz^S+i&%$w^uEBbg8xc=+PV zu2nH%F@u9)6L4tzb@Xi&=2L_0?0}B?Id*YTHa|8V!cZ`=fY=9hV5fFf?}Z!J z+DJrLKtnvt=d43m8L^N$-PSBwjHV%>V$;K?k)dN7-^N8V^qV6E?J~}(cRFp2`??p( z&QJPY)bkS?{*7w(wcenaiyn1`Mz*KyPvcxA!aVRkLL$UWLv7u)hodnd!Bhn#!%bRB zl%Ko5b&;X`vTQ}V_|!V4`6O)lNzGQ-7&z&nJY}I?%^+gZ(?)3z?CM}O7E_+mZ@|-# zg;rl>iZoO`&7Dm6h%X5+h{8LOx!l&|G-S_?KOTs4H7wpnm9x!d4^T9<45TnUVd3Tt zr<)PuQg%=^Nm)!fG57&Ch}ELV@GQ#2PgQ*Yd$2wb1(i6$h;GJU!x^aRAZ#=qZXWia zFPhG_BE()-7nk?VBDU_GD&90<7)r`-S@Jvawk@*LD1+O+hN%&LC!fsUw=lPBAiU1x zWXO_HwCG#4xs%wQbNfK1r~#@wMhTYCD5g=)!WJa)<@_KOVI25`Tg7}y184|f->}ap z>2$qzg$C$aN$on9U1eCEo+ir15vp@|4T9CGFffmaktM%)eeXvAYyM$|kCG=p%ge=% zR}EN3HnE>cNg{n=E(BnOhu8A_!YJ!4u0z(!HhR}R4rT26Ha)yL3vCY64dQ6VCGP}M zP8*J2N{IMLl(5-@dQ%h%Bi~;7YZ9I!<*10R`PpiQ{23neyk=?H@Do4&m8Toq8W|ZD z>;Cq*9U_8}w*Q-X@u!)`+_$0g2KI@~(afQh5Ibu#>E!$#!vfD<(}d*oJrFw7cuOXR_j3)aUnB~aG&VCTIkevnlM2K-0|Ef zlTKEwXSYv-Pxd-NTW#!1@9s?7`K~pbB?jU@nLoaxmw?a zD{K|DwXUukVvbja9Q*FHT157@GXs0`p$gzC`kD5)tl}}NcR3o5!lHf)`drn?+RO6K z>;Yh)5CrkTJ8<58Q)O2RSH9OT0%gn+e0v`0jqp$KUXF}tT10hO*@LzB0rK3ERNP|y z*Defu$sP_4$d^W1Vaul5fIDCoxZWPjlf^~kR@%I^ajrW{voZm@+&CB_IE?K7Rf`It z4i z+gQWz)dzO(>NWmV>>e6mMkZB7A|Iz*O>F+v$ocJ5x^+vZ@m6uy;fN#bsCr^uP*>yk zTpuAC&m9|S{l-K2gBA{jT35$~2jySs-%SpUYR0hqMvVp{Il+0yHAbE8iA2nMnaOX5yzr}TQ>xQ@LR(XHBaVi zy(IbC8XouM2R0Z$fu*l6Rt=R>eR_;pmEF??y1_$-+t#ifhP#7Xu(qWjF=)DB-*5QlUJB zygmcxp|$&-pS3b;VKwO&GR-*|7xM!yQ-j^16C8MfQdt2?BD+Q>RnU`Lsy45{W9web z!i>5k!#q|DHfWSJ0-1PnL?&C!=t1Go;hHk0iVM*5gd`wM{z4Y{9JNiQ>*BOGG8RbH zV^qaE2@)3D`rb`=0eL<*Z12hN?&FMs!4{DFpk3{W)mM_M=<4i_-qk-V51bbBIiOum z;(|~nB#7fvWKUHJl7aFHp^_HWKjB{#gMti9fYh|(x%{ii8Va*%Ph}zJRNvoM#IOWQ zd{g0zgA9*wb4>Fh*yF*~I=JeP2CApN-oheJtn!hkGCTf}$fyQgeylw!0w#I!+LC|rl%Kbz>rjH?mi@#Gr(Q1s>7R(|Jv7Vd> zyxOv5*>CZ6I#C88bA>eFWwL4d@I|Gf=6BTTAK3o10wd(yY4O2zF}5t>w@AI`CusIU zIqy)>SK3P|eX9h5xNMG^_+iYmusg6|x%EiSYp`eTRLN?J+o$fy)rjSsil0{|YxlZZ z3m+w>>W9fZNPPzSweL49VQ*~0*A>{mi8gvwEt`P!DO&waRPQ$jOuG6mVLzzCHHR9me zZYG%VDJnvzO0dN&{U&Q>5nOpq*L#}V;W;bpjUxS)h@*nuWGS=R{+Lo}NX)41CSW=% z5yo%{UP=GMk``}Y)wQ;hsKVg$O{G&b)xmi}#j_at-T;*DFqlNUYo|uiX)`sesyRBn z*y~aBIZcqLZ%LTl{%L`q&9GcS?Q_IUE5$Cs#Hpj{N}HaD&ns5k#MgbL0)9uI@86ds zA9GF=USB9->k{k2#7Ggh@{Z6*rB^{~@VJ-QKDsW$N?4G74%_~IGlZMrpgW|H!hmGU zrp;ZC)sZAzDCI7)B0GvNDFa#Ra*X|CvFDF5KEti*4{eg_xa_w!=01+6?O^}oPYf@5;+-hK37zQVx}$1) zS|cQl_1ND0IBvrDeebmhxg{@|4mn--E{^}B=)C{gUf(}%@7=_Vtw@xLReOuQGVD5b zB~%5qI*zSUMQkZ*BqWH|D%$F?VzogDRi#JmQQBJF=kv|?KY0K0z8?2|U$58mSt|@| zvOcBRsf3z=p%f{x_Xf$T^#T)1K@PwtQ^Is)Gha8Z-wmLC z=9UGov3jzOD--Sx8`1StP152$=xP1U#Y=l0Zc9$A%I4Qz9dc3M+dNPAojh5&u;(xS zjs*x}#6)R|tUvdE_1C}(?oCgY(k+I_`=X>?m9th#bpmy7oI;0R6@_SCwc51r`*Sjz ziZpod=~9?kknvFE{Za?hG;oc)?hGn%rEC8qi+)Z+jfc4Yp39LW^W)GZ{MBz>o5LM9 zS>5#sG2GSKcQN6I+Y5#V%dN|beDf9`4t=JZp2-6C{H}z(y(XByd8Uv2^M>G^sO7jx zh*UXilY92?Vwk``7xgq9tG_zpBE!^j^zviDValdRp;KY3?DrN41czUF%6W#a&y{a! z%=z34)@qEo0kqm7Onad>C!~lDD*d;Mu>J;#cF@YamN)Fd!9mAQRy5k@PuFmUE#fzx zq$$y2hT<&c)q$R|{#~_1;AvhG|Nu8$UQvsq`m7M4sJmuwCWXcsAgXR#6a zad6$aY>_xgPMH*vUW>`BM!tsQQ#+xIDgqYb|E`t?Ua#~K;3qCBEkvTS4w;{zHcu6wC@!p`ft>F z|NQ~6V_F`2s?Y{CwNWh;rP^c90i?SUmUf%3HojW#Q~20te(D`eNsf~mQh)Bx@U)vI z`Dw}lq)V9e;4f-b#_C5=Z%l0lzSyPZ^RC<;CnXJi3-Z2FXRFk0b$FEn^rYRX*aSTM zMlZ-kV4;Vtb6Bv6#cpwq)22xgWyvOusxAj&P*1o+?e%dGZtlhX zm|G}+pZn&n64F}lt;vo0^>S}KM&u=1(PF1efWa))jW3!84WZcD0K_Jq@D4Rsb`G+; zAA28@j+aEc=YeA^-jDS*o)p;0Ty>`kR>y%?tXsgQAw;N_AzQr%5xYnfop{j-?`zXP zoC(l`UFh(8nDA&+*Uej&Ce1l9Tqk!ro-MhFdQ^0bQAKT6Dm{d~8pJ%PwKUpp(|IyE z^UUPOKdS0=EYYj_C+~#gVKP*V`i<`*$c?X?#_@@vMduuL8dp!f^X3tfV zrB1iF%dIc}+BhEO4qH!?eV&L#UY2YN!wvMZD|Pj7{dxD(;~bQv?)&7L%Fo5pq&PeE zK~8(jSVvJztZ}BFEwiZaZBWek(EBpSh3kjp&r|BfF^wY4vays_gVgH9nU0sqe}pj~ z#GdZxJ4r06IgGZ)&(%jv?vTX4J^kjGefvs%^CYVke&P%`@VVo4g+`Zh1YMUodPBMw zV&X9V`p(u@m$n;<-3;}JV!Eh6t75C&ShIcq4o_QQsg##7FihOPTHH>te^n$=p{*v; zA2wZd&<67zP7a`16MQWv?DO$@o(j-+^IIL-KxhSJ)U<3o-&Cn?x+q>xQL#LsE8FJ& z^%nsG(bgrRCfNA_pc6BSTm`-ocy%ERfDxJ3MY9#~Z{`AY7xkc5i?o#gt+5N;dSKzqN?;=7)V z1-_BR?W;@hSjca0liZo1mM^0~C@!fS>Mi9cHL3cSFS4MaB33p^;q!^MF3lnPTb!$3 zn|qhu5LYR=?W^*QL4Ae3*rgVfrUn?wx5?eK-B(~ z>YY%Yt3QL9H}}8!(`%t)k{-Nt<%r8nBV^$q<5q38_cOG{8Y1)8!W|~6rWxz=tT?1e zYyo&1nPG+Ney4RYx42Og?eDAR}rEtRgDij#HKBZcZ*g9f(B0l>` z#NBM`q}3ANd~)SOeQ%V-bb|+5-xO#V@m^5M=c@rE0VWs=rB=B6?4djNuH2u(whL6A)2q^^K&2dZ!rv?rrP@jvF?!m2 zbG6OvRJEy9JCh(~9LLCGJtF%U_+_BU{4nSy4Js&-J_goCQNG9OT80+bv8Z#mtMj#` zG;8FC0&-cqEYm+qPPEKOyjrB{WpeiQ+d4(o~ z%=G`PTGtu2J^tq=e);M3w{bt`!aIkdgZjY^YlM8Q1^+d~Cxt z%;?wXU4840=pwAk$A?_?Khi!@9%wXsKEk?)T`KZE>Hu6K%2(di=ZJ35w*yCxt%G{9odt_M^q$XQ+-n3%fBwI80#B< z)r?UaVET)(vN(C+>R%Gq@yBBgh4!~fUPhPeQ<~7MEJ;$K2mX#R^=WK5pRR!ubT3^J zFudANOMpU1FH@xxL?G#SxC^f$%K?0TWpe71Gg5N(t^TFX&@EY4KGFqAn&=qsBq_qZ zl93;FZNPQ2pdm-n5U`;Nbz2k}zTM%-a_QHMQ*8dkyO=WLCT_r7-@^{bY5l`UI^+vD zcRQBbslm7)FL~N{u8dCzyl*Ml)FCj)m)NQL^MUQSYAN_c&~dp;!gT&gfJ=}E7uvra zY`I>Ob>)U$P{HXJGdojO7jMOt;p$F21MzgbBtp>S$!rOod%(=s-3E2;*>9X!nsjgQE|!wj3x>Trqt__aA?~0$<|iyw!Nl8jpgo{ zt8+0NMVC!Oo(5H*+to&%WpqP`Z{Z~g3SR?VBabJ3N{b;fBHxScRL_qr-bRF{E~KkT zwb3v6p74-PI#AApD{rvJ<-b3tKG z58M7|M%+Z83yKT~f`^3nRp5H18QSfb%}`(oo6k5f7{E{$^tHvq{NSb?=^$w zstd|sp*}*V3+zd%Ieu2Pl|(3w8Sb!2pqrGDR7B?itQ`54lfXweEvD=u``3PYxel%x za8q>}?5_)*Pf~pvS@<$|&I`)0FeIN%bSfFBZ3f1@e1Ujlzu|!YXr$RAPooV= zrXxkZ_RbZpi8=r>C+m(TcJx^Obbq8@QEL^RO7DH_6av~zKXmhwNdXK?p6)q6Icp^6 zhJ}(86z0q9Q(^fRknC=(EyuM`FDZUu5~@hF_Ox;xbyqOr!(@+O8wbmEvR1-R$! z$(H}}1#aW!eP#+q+*ncblJPjwIg8UxrjP2=o=c6@>U{6~QU{4+bS-uo(2skmLKj!f zrk73Hjn61^8_fOlW%m45Hpu!_7D|~J& zs*g(xLfZb(_=Qux*Rg_5OewjAs(TKDAY%|^MYO9u>LB>_rmpL2D8JDd4Y}bmiEC<9 zo)=+nl*6t!tXltJH&S8T>)U=PjVoQ_L-TfI9U0P0Wg9BHKZ#+N3D$tPcz7r-NOHY~ zE-ungkq;MA*ZZUxZwZ=JZy4_D+s^lNYZ&gA`U``0DlU;?uG4t~Joqm=mEv4HBTO<@ zbZRjP{fMEKCAuQeDb5<}@=}V2*$_T!`-q=qw3?9oTAmf{z09UI^*K0LXhz}ed0!6-+v z^rXaw@Qh;?Iv3>R_~kSzMC~6T6F)+=DxRI2x$zfNFJ{Gur@rNEjtUHB=}CCnJCtSw z+?vwTdVT&8uImlksru}yBTdv|1$@?)&h)>~U3K94?~Gqo-&s=?)Nah&QCq`!-K|G& z4(t0?EKFLYa_PU6C^ykG4V{^CYUF=k8f;hkMOr(k2sdNY?z6DPph<@McAGL^dLm>M4z<_Zi)H=`=p^vu zCcG6K2)@Uje?sGY+hZ7XMpIT82l!a$a+Ri~&a<&D*7OpB%$Oa~on}lVM?Ad!*1Ss4 z4%5(awq1j-hKmqE`SZXDpO2joi6M$S3(8*24C9LiUWPvHKggdnWbcXj@Kj_GWOF;~ z*W8sH+Clg-mtkv1k}}CFFOJI|h|%W9RwJK;y@P}I>mHlV5re=?x$^SlguEY*$Y7h1 zl-_uk&2NQ;(%@PPNbJo^$ZyTTS4;oyDkeFj0aEFt(E_4*Rdh^gK2GXMAD@e7tzuk7vytFwCO zcRX$qzrl^gwqvyWe&!oW) zbN{VyAHn{X7NTI)c+$~N&_w+4BK2ui_3fUE@lyACy)9A-G+?hBBW_fNEpF9T%x_Vj z-!b!ME*|ekAX@M>!NivIGHRcuxE9oFElmiD=uSSI>-Ow4y6E}TQi){;aGXh|Ea-Ft zX(pntZMu{Qjp%Umvak&xD6e$I80RXe(*e&_Cb=~xPgP6XDiqj(Jsy<(ZV}V$psL^> zRbuzS86m%s?au8hNZ7mC7+LkCUA|SvP)KXZw-%4BXLoN3U^l8GngyWw2~3Kpm`ik3fh~!d@70Qk8_ak_2o92zW-}Hg93)N;j*KSspFmC2y&G zzBu*|j|$KuxJ#;IOtSS|unAK;#Tp6dW?oY2JpW&~nkQDk=#GtK?XFxeFX$FvTI1Hi zP|Kq$fW=b^I14Tfh)kGZP4V~TS%N9u<*k+0(Nv9k*> z@=^!|8R^DLNXt-f>+Xvz3{-DDCqD}NDX(#Thom~<7ll4_`(>P#{6}N?S_U!vo=oY9^E+M9?pea04?N(kt0O_2g5vL{RAFm9gDmm-|u+fG1IMO zC&`b}YT{{1b7F$JM_2MSlxwPG zAp^|gtC5+>Ml*oPu>3|qHj7k~*wQpw=ldj$McwAP!uq40=lalq!jBUqv9)8KI(^x4 zSy-eO=aV?_)YPh=6S@17>%{R!I^9X83C$w4k?Am%T7bS+RD@;^CE3kYkA^Za4sG^| z93qfXY8vKE@LLPN#<(RlSwU6wh07kLhcvI=`^|uW-YWBdo%-26GG8cTx^3Us47Q>r z=*M4O?kmfkVOhBg&>~Csq|Cpp!qX&ofC@vPv*s4cq1)K?GCu`*lUTG$@9Nu(RMfxf zx*{p;_4SQL)2S$*fU#h-vZN`qbKQwAJ8k`(J|qQ%JFsvTt^I;)>O9->VbktWAztUW z15W$rwGYBJt6i8Yqs^-{Z1d}KvADK{{7uSh(ocy%55&JfyR8k` z2S#Bsal%fmD(U`@{p!^-olk-i4iP3t+5YpmCjV`^+cB#ci#=dg&qgUvf)pMwEOe*U z=VYkG+c{f#0Dj>bG(I}~VI&B-`16{4VlOp;nYGXr>S^VwGy`|0;HPbxPJg6OCG|%B zEbl7M=YF#b#7zi)Bu$O(6GN<;@(atm>*mk#$6x*M%jwJ1OA3jt9?&v)n>aJ_`q*BQ zon&@Fw&iMO52h?1^ic91V18m6jf^uxZ>7{d#Itt)LcFsI!2N~cel@h`pk?1{h9+5p zki?K8+(ST>=WJ_??B1J0H9~cP`td?;J!R|i!@dPe`nZ+5x`VNnw{X4H>g@r8ZUd;Enf5Crht%qtP{)ov!jSNh>h zF;Lg_Jpp6|?Q6Vls;PDx{v;rRhuDmFLJ!yPT=O<`Qc?vqJ(mInB^I9#U69_ z12~uDY}bs>YOC(g_`htx zDz_O*W4(UJLhPP(eTeb;V}Is$Zx|(JT<A6rkw3*}dh1nwo2gx}jlWvsN>*fP?Z}tIbn|BeG3E^&_!o(qipwdjXoYe8t1Jo; z&C^@}}^63%Gs<|z??o^LeY3e=t zm4;AL>pi02jFVSDlHRCq@y6Dk?_1$*Ln-@noVaylO}Nm6eMUy;9EvQ#~nwQoh!R`KSh z&@A-%;=g4(LC>19Mq^S=n?N^B5rrR`EIuqpvb8k}*m*pw;BjoN&;gohi0#8t3~(hr zt@-KB4nFzYJ<5f3E$3ga2ioi35i$gtxk@Q%iMJ^X(rtO<%9NlpP6F?OEywl#^kbMg zL;T%udasw*2IaON{9reYcfVA%hLF5wD8+2Z;3tR$+Aws!PM;~Fz`9rv7IrZn7f$rX z^O~NKtJuSYF!K&Po5&ym@m;idRqf=TjUr>@HAuGc4&iy4vQfYe$s+{jPExj`T;N9i zuzz*1=i$(=5{5-gUXeVfp_KU?_tEtaI6?tw)f;4>_(oqQoJ)%4QDvwmrB~!HQVOZ8sl^ZOfK*K_=o-KRjnyFVe3Kk$X z(^y3IIR%I&=52>r8<#|II*3D&H$eGePgOPep-DS zps-)~P+?fdJ)4TKVYiA#sN9Wrtc95Vnop-o$mVV)kYv#{d+(Z*tjhwWen<0G=H)8 zvzkk@aUe4__p*D<+_-X_OCbo39DtaHF?xcVw7;O+z(+=aP&15^%e_;wKh;OW;|X(z zvwo%!u1vrP^;4>n>9)cbqfDe#VJn_CLXmZiJBcA<%rZ`)Q?1GE^X>K#?w-^OEh*h! zzOCfQ{EZm^7=D8Id>qGg=HWJL{A;s~!5rB9kY-N@@Vmh_nf}>gn-k~SR0OlJ>S#G3 znb_hj-p`GDX;ep!0XGNhmOtxOsE&9XISa7RkEF*ml`m>Hvvt4BQh!IluCX3?g>Y0e zct}{U#&N&N8lES0xEh#vy#NdnuJY9}jS08C_kBWd3y!fI=x`_>RvFsFx~cOgP#Ob` z5&5^*?@K-Pf(o3HH}jZZM7{T83#HT>XdW60##3IW|~4da5kd)^}TX^H;J5|%(S z%Gl93uFdJn5^F4f@DID|6*23jB6)H%Htt-HQ4}|l$z)v(Zh#hVd++~C8~lVBoK8|a zuw%Y6Ift>`F>C@u(DxP1Qs?hqTf&7E-;mu0^G=%-lpel=3j-#r0od$nzURtt!|HW z!3aE~S^rwEU$God%>j2h+;ED;JBKZ-+Su#yGs&+1N@%DhyBGtQe|ShWNTpuYo2TU$vIryNp(ap-u@ zjv?aeG$aOY`!dMPPKIV3!0zC4?K8aZlS`OXT_>SE%xG|%aB`i*d|~Sq8Y2X@@@DIA zd)jONkc$2%)k+mpUxW3a&Q7wCCP*%GzGfJA?T{|9yQ%Y|8)lK)7n&luh?kLz(chYX z)O~B&Rx9dy&I}kPwKV*dnp|EpG}L$Je_MgM%P?Kys(OlN)o$6UXFh-YVt2!QW<(^aXY0$Rb07MxxyI$sZYW9$pP@J%WVw;e1H%lU`v(Ge7{fQ zG?gwi#U-ZDtiqTAT{DaV)@^m%$>w5XEIH?vXD05FMsdoNG1Ap&9Pm)rA#||iN&8q8 zuOU6K+w<*Q*LlsxT+emyEt+{|!B+h#W#cg2lVh+|R13;1_}_=5ktvNVAOh08R2q*A zgJ0~l0|}>=i9}>sV!f;tJZJPBr3_%&>LJ=Z6s`}IL`CCJ!X?*<$r(B>BV@=?{|0Y? z5QIO2gSoUfs)4y4bABc$e6%vdXgn28h`rO2Y{g$P6Qpin`|-TpXJan=T1EZf9}KVX zH2dZ+6xrAG^`o*|d^V~X?_m7L@gLd**vIU2>4oyieC==j{Uz7F)z!Qja}f?eI>+MP zMdKdCcuw<<_bA*9SJ+s36V#y-P#K*(pOq8;_i*P zJSFeH9#SJTNAU)dVW|t7m4*jDXVqjx9Oa7#4?hSudwMBG2T@c~QxToKO_RJ9rnf`q z(m(vF2noj?fe%j}_w6AYN_Waegc{oN0OS8Hz;z>GMMXyEExlrRDXC3l`-Tzd8sYWJ zhY(nb85n@~wJMI=>G56Rw3i0lyGA*1GTvl#h24j_SCpWBzploGy&k&y#w*S{+?IfY5(x_zz_);m6xUeg<3X8vh^0oJU86Q z{|^~=zp2PP7V(ARM+>=c=nFV&??AkUov^$wbRsT(scqr32wHqi54q9*$~i>U<$X;m&cg zi)r~>2w4#wqBIuC4|mzySA`~WnSr+h<6c%W*Tt|SE-<&e4bn9`bo?#Vs|0Pa*w)W+ zYaxY2gT`(LW)j5<(iF`EuNJW{l2@Jr($sCDTS4;ZKDh-3`e|+82MrUaZb<#Z>bK6( z50TQlS#FT7=N*YaKFIJRzjOx>BW;I-i7SaHMFwX>caTyMY-K~LuVgx0bx_=lAe7o` z5Gu5FEdIE+$GI4Wdl>P!QaxgDLO*}Gv|T$*c(L+xla z1<lyYz^ipUlTGE;vmYAX$@Hk1^kL^9VDpM?5pQde!)UdKbB4WTuL2Wx*Du#|Pvve-?ZqH0 z-LoXa;N|?dUmTNnSJc_-mt55~FI5k{r5hfh!Ym{EjXPGNDtAIs7XotG9USQv^g|@D zFb?7o|Dg&*8r)c{Z5Ko!;I04P$}S%fK%`5y3=Qmk>^nfkfgF3`M`W9@n~h0k=oK$D z0dx`wX*IBCBaOz5*7wz2F(UVRKF1|VfHm}W6Jx>Io#-UyEO*7b8mTs};si2fBm3H% zQsD`no>g2>#}{&^0hegeH-EP%#l3puhcz-^kh^=EQ0`}?9N`Bp(4A zU=*xxY_|{b?U}GHfw!f!dJc^{m0F?&NL%twvG;zWW*`+)09K?bC%AyhL%IDJqh$gZ zMM}Dp0!1SpZLt{XwVOz}ih4;=H9S~=oP#oHz?fBSF3d9yFA_1JmK%sM9OFXcA4|6K z^sjlj%x%2Q9^8Z1t>e9WOtEgG2JVuB&G8@Vybs~rn+Vm>0b_XVY9zNA*kMDD$MlJP zfLCJUGxb8OcUZKSImP10pAZbBWT;%$l~3*21_Xd#{S6`U?wIXwhGHkV^>mSL_wJs@ zy=zqvtWxM`vgS$#p-O{{*ot&oiJ!m0xGCg<8WZU2X60IAukzGX=_=MCJ^rdj+3vkU zb1V(EDB=0%UEV1@K}j2MYYre_u%5O9MYSJ($Fql)6gqh=uu6t$lq~kV4mC7A2eQ9| z?ORzoHhjFvpvW>1qP<+z%p7=3pjpen*uyPt?JplPS|3&gS42<5s)JKxw9PknsD2N= zXh&&H-&7D8;p$c#0^uj?s+3YfR!<5f6TXo%ckm2k{<{efgX2bNP(=eQdZbjsRD0P=5U=C1^v&VACA3`{`g%BS z>%oZgo8NOWT3pK9EJ>=*l8ZVy*)fT1RUDQ@fM7rn-;4X{R~c)?vnP;+xYP#@X?yU7 ztuzwwk|k#Z)h+Qz2d>+b?1@^9gG4kDSOF^5tQ_I)n27~VKKbsE<7WjtpFc&_;aP#c z4ZgsJyQmxu@bHeEae0zaO0mZMV8~77N1@2sLs;uetFHdO-q0~#zlKrBdf#TM-iNFy z=e4l;To6Ku8-#46DlLrxWxha$0vIuz(15xPDf%^+AAP7XSPJm&+8PLT-F#&wKvynp zJ&P$M@d#+S&XYx0!0lDpPtt9G#pIRY_7QQ$H?^A%*9Uz=?=Y}=Y!)tMkD5y zl0eXdtvXq{^FvM!gQ&g4jYRV@)Y6lGl?^OvTogXUtqApq#w&{!;*;4(lLN0jokO4! zgb~cyE@bXK#}96`e&PeuzH!q>b8Vw_Y;JcjF^EKE5oRyRHP9hvwFT0Ri70xR4B~s1 z%Pt$~wCR{(+3Gn}70Wcc(XE>ks`Qq3RVIs}IF6Lt=YX|XLkcjq`;&8cN+UC?Dv~KV z(L8PL0YS=?MwIpN?;^|TJRCxIT6nt`!+!+)(Qr+>#@?fm25BF1t+aQoxWS&Zfh0XG zlaaIe`u(jJCFkcH&ybql(G*I^=uOA#usfKx#^4`?2Unl_D~2B9^16SalZ$~C*(Rke zjWaP%b*kl}g!ZN;bX-#@vwC~F4{z?wqGTR%?j^~3GXBTXIaWpoCO6XmTS5r>i9fq% zngd*zT;ms)^lfq<*SGy`gxr>eq0INypJ}|eD_uOjsruMHRw|xm|34NU&Gih6Zf;p~ zr}E3Z`=bA2d9@DwA4}r>x}E#`Y@xN?pS5ex)P5@`wdlkk{`=8nkWCiyvW>oDCt(A> zI*H0nqM%Ach2oL^E{ui)@sImWjo~lum-iNhGJRy3@o0Gq8bWa=r_J_xkoJnajh7-5 zkTF~(q`EI+?}vBFJn(h2ut-K8KrKeWRejQy>OF8e}A~iTkU&aQWeJQnHjFIBiNa;NDV?mkc+YJK9 z6S}}u>a4iRiQ$233Uf6Ab6{_eWOX>ev5nRSjf3F4X8Wp=peuTbn{Zitkb%9Q^>7_W zfiBI+-So81DBAhA+&0ejT|-S#p^kraB4zIV@?#a>Lj+G+o6Hq2^?TUmTBao3>qUFK z+wm7eQXCE@kMR_Oe94;6QYss4Q2LBRh?}5JM8*O0a^L{IK<^&Cac^d1P#~c$Nk`57 zL%P@DTU_?rD{6DpvA#XOfee%KMxd!}L@UhQ=}8qCT(Wsh?*d&L#1|ZEGV7Yh%kS>Z zMR`$&@LFTvv-}j%)QCpsp1k*#PARm>R7V95BcPl z%yjOavU73^q-tT-MW$FbKGd(uC;kR++e(59NjlQ~R|1U-s+z%eYO%Y9%b0$AT*`WN zpYmJtQreVLX6)+thLhD^chFq^8Z$=dVlbD=>R^`w=)%5TY+3Q=<>hXUUih*WcDM`9 zPh!EI)^$(csV|>)89xEjeV+~(Qh7s#vg8^%10`~TRsK#Wtn~0pGElD6Sxaj9Cfpk@ zR3iv$)+Rw-0p4YF~VM6?Z2zS*U$tQL=QiE zvjbhw73@$yN+H_^BV0xlt`!+IIVJw6j za3L;?m|ipw3kvPS3V*&}k~?Jj)kX|<=d@lVopDMv<9h$ivg9c0V(71{yND_3&8OnS zk~!RdqWaE{O8S9 zb?rV7&e_YLE%$K%<6%Dy%B^>l@7SsU`?1B=`X%@oS6$x*f;4dId|(=Nc?{-ywcw|Yb~4rI^tt0$An@lp znf`I68&X~VEv(xIu5~^LGi#78~baCx> zyJ#8Z3_(~|5?v5m5bvTdTT(5J4N4{#N5{LJSP=#JC-$u33re%cAO=OOOzFyYwdBo~ zU*Adp;vEt%@v`b6MSG1JvWCa_m_YGrB-6v;4$)x4{Q}$Gga&xLsEw3-Bgd&;(9928 z;j`{%^+UTb23#eXYTT*UEM%FN5XL0)z4UpgYI@T(rK3JIV6-~WPxvhB*FvWem1tOy zFTkLsfsjtxU}0q-XQ566zO2y7QS7LweAjq>&ia#={>%Ur+VI}Af3R-3DNYFUTU=93 zv&2tiukOqbeWg>U%=TI3n|B(ID)BBQuB90vcNXSlRe0{l41MA`@bwmPk8#Y$<68X_ ztSNV@CO_yce)6)kUu>bBRO1()-i#vl6^6ZGRo_q^xb}X0mX(lGy!1h{hY})LQRp|D zqqT|jv`cFSChC8q$cTnWnTAQHzR&2Jq_B+3wglCXRku7b#Gw4z9>s1;R?pA4?kA7N zh)d8Jzp#E?GivEcuN*_OQH{U4cA>6=GV$3)C70ujovkvyv*NR;!H$Al>Ab@3igf3M zC3XSmn0FjCMSe6S9MebX}Y8acp?9coRJMO0Fl+ ze})HQAkeB1N4*RT?xFXlaQzBr1}!3Xk^;=n>@ zoR=25EVS-P@3CgtotEFc<&%dF_t@5{%Ol%Q+%hTOD7fcJ@Y((w&20|=uN{phfCJKp z9-N4-e9n!!wTQ>8R~hTYrpsN|my(V8hWhq4;Z(Fmf;{YCj5^@Q6G~y7G?I$)mUMh*k$9`rFfPq6ZpW>$KMgaamlB9w^fjciBP1ZLc)DrOcMEvsEuyVU)QuU@G8mw|zJ>eQ;06WX?~J zQu_z}9;vbWN->$d8LbF33^*wqT}XL(ZArsXljlCe!FzM%7URuV0?>dAsKcJ_Icl&c zschasOTDxqc<)^YW3 zuoYrpvg)SNUh1J4<`~`$l29BEkz1*OrldA?!o0iubAR!X(QuI&q;G0Nt_BjgMa^6K zN(lKqt~pn!vJ#t2VGah^$0tX+MNoH1=8#bA{x9I~pjaOWFknj`l0jDSusWB7Z_GmKywM z^%M2>U>xxJbq&l;E99H*yRE{{u#r7f?f1`oapn!Z;;tLp4{|>`UH@1bm-fdFb)>J7 zAAh^<&c65`hiSV=dj0aWkt^|ApoZ$fa7miq;$Ci7K2Be{RBkK%Ht{C2Z7%RJKHzZs z;bT8TS|0(*7)$xx((|%jz3;v0jSE84Jfy_PMu{#HMKyqgf|v$`e{k^jyVkom*a=~N zv@HvDW>@tU-j3seXF5zLQp!wy&sR)QieyJ(SIRbBFA__4y<6FQ-h?Nx+|!i7!qZ)t zY>!PL9SrXik3W!+{ByF3yrLZA=L4xH0{uT1=r2$XaqU*Su7RGkD5VDNug+pyg>|Ix z16-MeaT=(e|rB%pi0Lj`oR- z+2N&TOFXpPLmd`v*CcG;>Mi=Fum3D91vsKP<7I3oj@O1HAl?Ec6@pONyAYTWG95A2 zXQ6M~ueJvdOLxg}8x38V6}`7!@4X7=R@l(Xd-BEU<=l%T3aeQmkblA_b>60ixiq+6 zzFA7esQs#G`5#NpA(q|6UI%ot=d+xr^UOBo z687rTGK_NX1Is~voP1D8=Oq=Bd$P|LOI^hVTX42DGd)%!Jl|vPV0pcbK+!a!dffBwljN z3hk%)Wm}IKZ@1baMRHq8yghS4SZ_{76_oa0U>tPrA%|6Z#3tc35#V7$CTB_k zR0}YF@%eMDvUl6hCj4&c+P#7|hoi7Z+EHy2O+|vv8TzPj#wKC$NPa+6nZd*>t4Zw; zARynsr5$`M*y&o284Ufs&3Y?@h-eIq!+3$_6m|eOF2J;%%PT^Z7AH%Us3CC-V_9|J zBr%uP&#%SljlYXHZ7q0#a*P8~6dS>?u#Ls`%ltTs@Xz5p`wQ2V)=c?&Z}23^JVS+D zT>_F~44z1mWQT9qSkIY0kz;PZ&0ab_1|NdGKsY=TU8W7gwQi(@pO^uOGV9RWy zgPCJ!(h%_K*5EYe0+cQ-X#4E(#16@*l6&<4WwXX6bO&Rl)Yp_gTJiVfBd5IgTdRv{ z-{H+9+szg>qZv=jVuhlbUmf&o|E@}8i;!iwSYxJrTn;|ZpHP2xLJ#3eM*!$grr$^Q;` zu-H(v=Ano4tKRvv#X1xNDR>kESHco%4+T0|mr#`>z5g!oA{W2k)B-*gl+x@@kfb9Ufy9i!)=0he!+r{`VjXVp^=+#T}oBqM~~5|!PPO6By1Mfi)2c$N)WX8nYNiF8#)`cqjAJJ9PK!HqlEN!Fv2$H}*Tr%S>p0H8kIuUysYi?c z=eRlUlG{69mYM&t1Xjxn((U?m!U2+nj_o=rq13q)WOKPzWvD)Ki~LdJ$T@-`7V3 zhHms2pjop-Fp8JI)Rs>AL+%KwDUwTcnbfJYPQ^1x^6mMwRD{ctLdh&+70~ditz~MY z9~db4O5hqh$>NZuXrz#;JL5s^?Vp)@_@ww25XZAAAk49V7XcN-VY<`0LuKvtBY3aa zRUbEyF2*|sj#w>kb)*^3Pkm;|%s|`ZIdRHs3T6+6;njX$REIT1zPfifL* zA~@y*s(8)-X>K-~Se%giYYS1&8zxWCKgJc#>RNfm33-FT@C!p^zXrSd#msN{8g6%>O&Ma)*<3X&yA_z*ScK!qV6N=C(R7kQs zqB>9Ni~JftKqyRWILg?BEIj$qdCM!Ce4-|4womO2%jcWx%odOHY9Tz=rD#fZi43PB z3d#iTK!TFn8>d6&r2RtmJ?=$BgWE5AR!l#SyOZ4B?D1&oY2taivDXT1AgZ>@B=*g| zD%NcRHItgl4WO#VYE&L}XgC1PyBR?%g!XazLkxRCMtiAwA~sm-7on-1mpxtMRjoeZ}! zYq|C$xMZti<2$DKD8J@vl6Ld_QK;*L?frcXBVvNZ72s@@T6gSKnaDF@`SOfs_S5U$ z2dB*wwY0I;LR!ZIz|hyZwpIb$bh%n*KlEiRlVB>78*6thN>*qF=@-H33X{*5JKYY~ z_>3Y2r)S!TSwY7fc7VBLLzK!HRVrL%O?r&+a7$0ASU15xUH)E)+UJa(-PwTb^t6M5 zvJJ%5hpsS36^;XFZt$g&>Y;%zN^@{G*wj{IK>yFCx{Z_iSGVv%2r zGu`1}l}YUVRcXie^mG*=vmv^VD`w##=hXjLUO;^{zAAA1#aBrL(=x>^r_70CU zk1V#x&x)MuNWI)u}j` zJ()7}Bb}?L18#rA#<8`u8(geA?o{9~QY@1rD~YPec6@z}dv*b>1MLgK^=WYh!NVnc?iPxXV@a7`_f%3N1lt7F53#+U^L9p$Np4h5Dkm8j-cMn8OY&eXW|z;pChQ#=7YcKiiMZ@Fl9dL%`bW`Y}^GSicPqtywa1d1UcA~S)S(SC%df=9jP7I!IqQOMG(RFIwXJbhnz zpIt^Xe7B$WHALwiLVCep<)xAC{{Z#_8x1QA@=N zWOOErWDajB<}}YKAhtmsGvF<+-zaAhxreMfyM9U%T2O`p_`LN zUbM&5Wlgy(dYrxHrh5MaVIAIhFZKBRz&KY7Ep1~H#ie}L)i!Be=Lp_-SL4ct(nRz6 z+SZoXKC;UHc6p(v{>cbx-(STVBe?VCtSy{y5Q#qcAT6Xi!D@Bs>jr*_UdQdn-`^8( zT)oB{G$-Fyl=yI9JLuUUt5;mj0I(fr;Ge5rc6={pq*p<VFQ$GFA>v98KLF)OT#1pU=a0B%W~ox5X6m{0L{VF?lX5 zwzxE)Pj!P+eVWG3lT4KSN0Ppn(igfi3%2&dpiN>dkcV1*w z?rnYQt1N`jP0EBZZ3a)d)_y3uY2m_GZZ6pN4UCyKYeHGIF_Pt)U*sd_bD{Tm%f)%N z@mk{CRr&Sa3=EHEM$2~SL~j>aE0YJ(MNw7DM5a48zZ%o6mON|adU7)W<>p%gb!)C-O(&o z_LXg$%C(-o;*o_+p0pG$(!Ufzo$6Z_ttepK_R^cOZF}?D_J=WxiQ3pLEWEs&I*jm| zvZf$yj0-p;+8}XwmmKeZaa^wrwA3EUXR@g0DtQb8c%L){bRN z$$!_FReM<{F|YfatQ@eK`i2WH$cVMv+L6uMdi4&|C^ka-YWL5^LL;Mizc^SMX!T#O zP+lRd3!O(@I3K%PldQN=EY9U@DPFX!<$b1%z`jpY;V^tZRQl(F5K$OPen8oBLwemA zpCv9?faqD(6*@2+$ZmN^W~@!=xmTW1{QsrFgm7a>w}X49VAgg515Dw zlANm&gSx{caU{c}6C2H{ssI$N`Q?x#IwwgG_6^~<+3KqMdy%LV^`+T?x442Or`trV zTQAi_^%b!#bb0Y53R`%?@X6QKt)rvvn2xL->zYGWhVnM73sz$BQmcq3i1hM;;E z)mMh;Sx6+;Y0t^2LLUmIpye7mkqj~+dmB$rn`KjMp?PL8Orw}S3aEu)dKOJL-TC1y zB++?)!d75;tFS2jpl*!+pV{bS#8{19aO(M}T{NyF z5Fey9W8t zVc(llmk>*t5SYuPPHpbevL{`ggfqpXh~R)(z$ zug00zh6HPHe;uX5HFdtIA|?fhCp{{Rwza*0kT#c`33@m$(@vy-&(^mMV)Iih`&A9i z!A1FyL~4@DZO8j_Y%u5l0oE)dRQ~g(*od0lxNFbP>$*Vy57g&xupMi|mn^2~`BKq^ z4~Ei2s>030zD3W~>HD3sTd6jC`L{(Go1(-_-8pMCPnFpA z%w3DK$w@JD4x#j#(dvQ(G>tG?8vAQE!-VM_&gdB$tTG&`1y*HJ9}=09OGc)R;fcz_10}^nQkg9j5!M9mmlP_kK?LYenn8DsIkpbApeg%Dp zKGeUyIf!fr?ZgZ9@bm{{+uN!-?g<>~q7|2#9lw}nb-my!@c|$uUeaWA$ZP$c`&;q1 zcJLM|lJrmIo$u`psvo8578TmPBI{4d)=$)>DIoxMcIr>cQLd z`Ddk}Tx{7Z*N_p%hi%NEjgc0H*4se@wW@92_OI|sc_M;EabE8?g(mxSIydlXcRUnr;i8oG5$ zcvf~j6wiqnzEzjjBYpI&C&Y4#q(=6IzI`<1!PI1^74UJXXlT@zfmZsxu7lo*erS#1 zmf-okct6hd^a+8)G3CkBq>U-Ob87)+!M-)6uxYc)IN`fU^^GysxCMqM)V-4G`|E$jYvJaaY1qSowWwOdYjP>QAxGnwp!G z8n(^xSPw)mhrND(`D-ThBzOx`&K9O03ysFb>rR=nvY>gJ$JMj&JZ5U`#QC#mBnG5U!g6^sU zi~#U185jCp_e_)c;b7#g(?VU3=ipV5PVL7;9?Kh030m_B9waCEAL zt^R1;qhk#5UJ=%>@S2yIsCm;G$&WD)O!7Ko?K7j0$x!n9c%6zVXC$!D&7bcnN8K!Td_(XXc zo_0`})HfLY*Y>{p-TR)UP&s66X1Mw2+ecrMmziipj{1Q>`6irM4#}&k?&^r7^eZCnkZ3{i^Mum+p)OLd}LCu{cd z$@h@7xlVlB>JFrurEwm*;ytOjonhVcY^iQdFo&TNOoBVNWn_NX{B9|&^J4H{=<}22 z)g1p{RT^B{5r4O#V&((A51gP+5!DUa-!Tf>Qwk)gfQi#RNAH#L7WhI(1o zH+ru9M9BHs`3_iE?%^lt-;ZVWj%6? z7&K7gNN(?g;AfD*Xq`;)PdIeD4!2vOVEVD?6b5Pjyasz!J;8d;B4VZ94ZowzX(Ww> z@9m0|Q{Py?WzNaUDBl5d5q5a^Kuw<03QzEW%OGvXM<%cN+tg~M>Z~?-YHo?iMP=tvO-DIb?^{Iu@4&atCfu9kcr8XTb`Ir~ORD7r|94%CEV_x%!Cv_H0j5+c6yX>zef8SpVpS zaYd1b@t?Mb(-m0`)>IL7BfSxyaetS$k95OCYyRy2yzhGPPIPvDkORDh*zWLYXdGly zdcF4`oS2B#=B47aH2HIIO|xFocz>i+J4xulvoBW*UV~x3W(sBE#ws;G9J6b>cMEj? zDqsJPN0sVVi_m7uU?hfQ;L#2L;n0&vVIep!_0aLv^8V+c0c}uo^~0eSBuW3*l3ye| zH8}MX2tN1fcF;c+w9bo->Z?Ci;R^4oVMo?QAyAJIT<{@i>p(HVy1#eGK6P$UUpgso zMxcw}{Zq2I?onWO47*ss4F$-uo~utou7%ox1b2B3 zRY|1RvTJsZ^)2j~S+4j~$9VjY;rUqVExz?oxFr&4<0IT#E!N|+z^h@hy zZmNCS>Vm3qs$7$j*xqW+v*5tLE83uOUO&k&q+s^YyvRCSh;AcKR)2MJB~Ui)yux_kTvw+=skeom~7+pta;v-`3?;xR2v0< zOX!`Wrz`>kDN8wxXWH*WG7qP+Jw9IeoShvDzOQTUAqq{YV6_+;e$|V9-jzjth#egQ zt(0X)m8LG5i0Nl<91o<9R$nEU985W<&P>P@>oyp-r%3bz%&U>H!!DRd2H>YKp>H98dDeyXm7 z8rR?9+9GnTV;Aa18_{u&VPxX^87!?Gz!zeyi$NS%gsox1*z?t=RR8+yWmveL&MMWv z3s<$&&A@dX1|#wxg;-A*xr_o+&;X=UIL1n(IUs^Iqs{a{f{z^gHoJbQ$E&v9yRamT z=B+opPv@w%$m_jWu;S=DJ5Jes9B9-~9e~Uq$)$Mi8=GM7OjDpM_%=t_N6zv{BZltM zWVE3IQGt6b@>5IVbalzs=yW-N>5tY?tfhM(5{~?Mhq_;YhyMqW4OkYyByR;NGA z2B{Qjt;iyG>-?Fx=sF!e>cyHRJ5`mYhkBxjJY%XDqn5~h?`4S_!H2#!_ZVk7`2jM9 zPn_-GVPKR-cN*7Rh^d8IbsY7q)Q}tv4Nqn1Jp0D^h{~S@`6nur%Bs?OdV@cKi2t>dn(Bq}aC)l6!YYRhhZDYAhaRU&Mq|I`}2h zI_Y$cMxFGpF9XHvDae%6t>o(CxVCmGpCRwR*prQl)C)0oY!sd8Y^tWb;z;BN{+5hn zxwoWsI?)Clx$s7sKut=C^$O4@)Vqv??KIN_XOFU&rNnu>l9?qHGS=zLk@N0r%M1Dr zX2z`kn&$G1_@7!Uuo1kDT#{R2_0Pt{V|O)L2Ch7{`|dB?u#kIcjaf)CMj%Uo-vzn@!@+5fkGod z@k(22#;=nmyj)Rx~W?I5#3VLH%$v__jvT) zUtE}<1)jJxQ9ao6b*%pBCpW3nwLZZFB2&tP-$xR{J2l@huUU&i!q%#?JFG%%%hsos zoJ4IeheX9)jlwQY?DOna@XR7)R*t=iFHlHC`QHg4bh7J95)O_S!U^ z?2DqyG}|S^Z}N|~;e643`^G9G&2qU`1;)=F6Q-?N)a_bV@4+8>uw?2s=G4d1^6YKY z;fuvqb%*$m1(b_@Us&-}-rWAth%po5gg`*j6w@ zbo(mHhx84Zc=_x;`yVrcx+kp9ONPLg(4UTF<fgB@KR9DPV_hXD{}|7LOQZDJJ5d z2z)>6Nn6Spajlp^; z)lc`%9DceA8rgN{SjZuyH-46;aN4;_G);xO@;o44cTu>hTCHQ5!zyu#KVNJIfLwcl z;B^AlM)qY>DK>WYY)FCqMyId*pXk^F6Viz!w{)?E={N_xj&`)FHbY1>c0F=dgh6;c zYBSn|SzF#oJjB*h$8A}OyNPZ!-LS1i3QU`yWbP~KZyu$-i@&~CncTJAE2P8m>Q`^A zy@`kaicl({T}39XBT&RPpf2O|r%1i5jdC+%xT2VxA$uQF^aLki0je2ILSEX3+nDR~ zn68ZuJ{#(YKCvE>=od-1+*wt&^rAqROn)`0`a0X{7a~$PaNr#$8UbodN+uPgm_k38& zF`^;I#k$HfK1TWc+R9ojiVu!0mQJ(UUlN5&vVE60so-Us>e?%r>o zwYojwaMvcZ+Iv-YkKjU3g-x#pS@^7vEVb-fnw0V0M0Smncx}6dLhGj{2^gg1ItkVk zBI-8$rD{RcVnpy_d5tix=**f3dRrg+mL*akX*}9I88S;A4Dzg{f~(~cE|riqH36Rt z?mu{*AiZ>WQx$-y;5$H{yxXW-OKgC>1i<_2Jj!O|9FX_V;kq@Oq(upf#19xtL)!c} zEguHF%7?L^rL?U8_1YF~+RCEu4E1As?>kj0kA3OaM|%I$wpm*c+O5LT-F)E_)U)lg zxmCL+oqO<^XMMR2_d37j%D>Bx8&J4Ke9-9?@}asy1&w|VYM+0^9}N5Z!Qmr1$X6L! zTXc$BY|)9R#XU2VX8b(lm>jUw>Zhe)`;wSq{G4fwewCZ8!Ll|O1F_=1sCmCwQIG;z z_*1XMg21i!U0ca4FGZQdaN-4w3VY3Eb)}Y*(}q0#Jai2PKi6&xbR%BNm7^OL;N4Vs z6a2BYLhQ6ULCo(SHqEr<22d#VC7oiPYKH9@M{sd@nc^SfH>W4Z5kOnt;6>x5EJLH` zour^f^z0jAFpA zBa6GD|99qf$vpzPyas%OS9aNcLx^{|RC?lDAw#@X`-+?MynDcz|9t36e0fb&4Mo2( zGVZ7eo)zA(HhDt7-4GIfZ!#F02TTjys-72S{dw-_qb4ae64L5#0MPYwYi(@L-=cdO zr4{0=iCg?TUm_jWVBoj+MszZxAgvclSRY$*;h6pOq!>7AEdTswOJnHMwP|5&sn(Rq z-wc*Y@1ah`pAAgD?)I0aMDs9JQ)%`+HRS&QUY|^(8zsdA7X!2;xECn6-JTnIGu)VF z&IqsuPnlh&O~-Rxe+ZWPjPC92vH4Sv(cPxQtIJ_o@;{O!362F@SmugNWJPH0*Q^R! z>g`UvOiQ+nu!eIJ*D3IqXv5t}ANoO`)NNJeS{3bXw}$-%3?x2Zr%H`)_Oiw;?&LFr zhLsJ@cq0Qz(Q3o;qwDc#-`FmB?Mm$m(=#EfQ?~sSo<;6fIb2G)b_Rd@r_%SXr(eL> z72@tEdM4`k6)k@>-*{)$`k66mtIgDJZm@2B*- zkU{hDG`Nx+7N%dJ3kOd@-Mb2pt4+~>`}wugm{JnsdRGe5-&u&}uk^KSXse_ZuBQ4jWdAe-XIjsJI;@ z$&_Xq725>L?EPUYY65_cog#~UC8qPsPLd-;zgM8B=>ljY=VvJ)eR~ZM>o*-odD*?l|A&f(8X_lPNR)`X4pZfTJ|WA`x*XYzD%#q35&u`*)>ybh3DgGZ~Ze zboV!O$3+h~3?BVvrARFkdtM1z!3Q;SCq53S-PQ_5EE(l7Tsnc(Yn+u?`Z!|K8bpR; zTz5&d++!ED;uu(|T+!QXJUeqHg=Xr7w2s8G7P%4*>3sYM9k;DAIJzCzh6eM+aHL0C zADxL(6|Ib(1KrkRD(^B5(9!kkWq{?*03p%E7Y0p+l9MOV8T&rTq9XuVqVq)!>3Iey zohl<$`jxKjgW5{LwqqF#f>*(g3X6kd+UNCRKD{Zu(KIo0+Yq;U|JnG#E-GLdZkrXIPYqx{tevqh9WtX3YS z%#Bzitg-@WwRthpK_`+rQ6AOejo?duc)rj=6S-sk0 z!kxvla2*KEjO#XzukOpx(Zwj^pso{-A7@gCZF=D!Cdf*u=2WfYr@#F1UFsC=v%xI! z7Pj*_0=9~}aeC5GXHzIWah56bmJo#QZgFC974C-N`@Yn+_m-%;;yRMO$`Q4GIh<}Q zWJ_sWufk}Mr4NgUOpSWI*;rccCTovv%0wYAp36t&5X+zyY(LdmwrKicp}W+vwqjlT zQ*y{mgV#gTfB^UOk{(~1N?)hD@!+$2OJ=WOFfAY^p#|;15QPw10xrapmU~Tx{2rQe zu(+=n?tS91GCXjw-`{Of*=+T;y(>W9Fj{uQ$>Z&>eN=BbErk>Q0Y;f)ZPChfQ8X7y zMOI=@S`7|(~ewQ!f52h5rcsX2MmaBv== z0hFUk+#6*PFYh(86UojW9Z-sjbPs{}01-jK zo#4_c7|))nJI8H4v=eqWzneMVuR(a(_K_RH^^El#%Q`J8x{)>RA=XM&Y-k{m!|2he zc(9sbP)Yw$L%o_w>C0s}Ia22MTG%yUd@6T1qUv6sf4|37ua&7AlIynebRXk$=_{Mm z7j7mh-LNqc&69wT;`7n6tMN?ouwP=k>}m~JoY-KWABY@=2PvB;7}~AsfcI36QemXP z>@zZ?Z(Qm9Fm2X^xG@iH^@G+C?j&h*>|fNU3Ds^IW>a@ha!aCTrK$3IsrtPk2f$~{ z53$_!P#QV?-%GC1@(B9(i_5U_EHQR(G?&{w@V|oy3L!UqirJr&Tsnf5bboMGp;v=C zgB@6tyi=&z@Nmoiy@%`Sm>$3Dl}d49o}#PqN`1z(ur*sJrOm6sOj?Njn67YaM60$x zDZ)Kt>>$n2&&~ex_4fR`FSg-d*Yn4>Qx{pXGpKFi)YUI}YCH>|o9UQt9q@FBjgd)pK80DaC#OlO!4vwY!Rmbv#`teP6;5u+GWVWWcb zXeE92mNi+c)YBC6>QZ174T|6&{(@m4Bn+uqz2b^vO?-!^;w80=NNop76r1?PUU03z zd%UQ4s>{=REJ}KMcma{4n&o^Mg(MiyV4|1xJ+Gxo>+a^xG*lFOr)=#Lp+bZR_nv2t zzWP-+$B3z+tB`OKvs2AEK~HaJN{{kS*Tn&*GRYlNc_X$cZoa~LofU1ew^ZQ(;1uSj zq66dQYs>VSL2Qxz8 zasW0Crli+pKCkU8M&$nt@W~p5Dgkz84iF1@0al_|Ymu=m5?T40-DFQZL=maNwQ9n7 z?By*a93_)GA=+=G=ZLPuLDD7Rj5Jb#S=_s2tpnwrAX;*N`J2D+IC zfQ9~o=tL6W_I=?urorEA6v2c5>Wm|U*d4L3YQNTdyE+t8#$GX7dXa)4zU^JpT2}Sl zMn8KY#(KU~8I8lo{v2mh-Rk?kYFpN|J~Ma5(Y_+Tk5GcX(x%5<2Ga`xyvEBtnZb5# z*AJzEPcQ3_#Lo!IcfYu>w0sAZCqiAA(j@>5^r<_H#&flL%61}ss`Zwh6T%F7^iv)i zeQsILyo4?Ub7~s_L!!0!(v5t^@9M=79dfuzFX|}G&#UDdm?JW*$i7wOZR}FG&&sP6 z6Bl0L8txy~^#xoi`L)EGH^li~bDdlXpl&{2=$8PiB)WM%OpwRN4NI*7v=n=oXP3gpj-%ag8QE0qyO(3mg~tw@cm7PUi@iI7q8z)N zPc%Qug@=j{xMyMJ*ojlNEy)6(=FLgWTa7-sPNO*^4;^c~ygw?lvQjjb)87O~anIoW zB{Eyo-3mXe#6cF>Ok1$|d#~FK?7Syfdt0r1?pt&lZ_0>1R76gf7YQHoFX6A)!Zadr^a^Bn(r~M!Ormbr);cUV~-&dn2_d?IMYB8=(}} zm9_-A89(#I{s7TH36kQyRuD4B%uS z_u|wyG-jPC)v1EE@bb^1w0W^nVNFLLG4d=oEKA32k{*Cn0T%T-6C4|rCDfEFGHYD> zn45Z^w3A@$Sj(Xd%ZTBPUEHCBtb!i)SzG3@v%mU8uz8Z%o=Ij{?ViePex^jinjRjx)Lc zG@peYgIxJ2neJE)S2*adD$X?6vsOkqD{9rLO=YsYYA)$Mu#_!(VgLQ@+w;?kNg;GE zEyz&k79F?14~VzMpQh{ioLtvAuE-WFZT^$`tHGn&-;jd&t?>fxRdW_;Pj zBawgO&7XYorXmiIPEH+&(fyauXlV_>(vqHWkT?x=P}f?5g$< zhIes$iUJ}LB7A}_F!8SKcF1@_s3Fg|*AYTocmpL1+1LCbB%h<;|Ov`utNdPfa8? zY{-3M>P-Kp@z;-?ktw_4l)2(|rM39WfRKgrQadppCh(!5I>hox^{ob(4m&ZNzNAv5 zAj&r+W{RvUKo(}4*Zq(W3Nkb(sN|5<=Rq!<6N+QG-W%&)%?s-C7W*puC-!_X1m>yi ze0D?sm&0{ztavUf0P;Gr?(eI4g;!?($IGYT!$z5<&V|v>o_nnFaw+@oA%INTp%_y+ z#=5=2xUnYSeyMz2hzo}3YryUK7X~m`Y^s#BQXK(roAab@S^-pn&6MI*CZ+KRA-r@J zD@1s`KtHs3xcxx~W15*s zcQu!wRivqQM&$uJVvp|+zaDsw?veZOC!#UJLm0Oy8) zPo`-?o`yIy%}w`7fIPe;CuF11;)R|+;JL5RXvJF)!`H59Bk7Qpo0|owt;?Dzk7IeQZS4PGT@spP6^KJFeoU>D--fh#lct zu|{8um2B5H|85L9oKf&E^5yFlO)QmRj*1%kfedR#e%sG&%IDl(bs;6n&Zt7j@kUg# zcmBkhDs?N3;01LS#b;oN*7AdM#-W17ASDaW^^GVHerO*+S_1y7g-E_4YX_EzeOopUyvu#cjgFeolUV#yh8I7J>_PniF@>9CL1UpEvB*prLGc z`~-I^3G~mKakZNaIsJ5Kh4gL`>LV@wh%Dt>LW1_FxfgPuOHPIj{C; zNS@{3rgp#hbYk?AllB3Pk;t;Cu_&ncZz~iub4y&m`Ww_yk~1L7JEk_l;D$;^CuGI! z=79A1lrB0ravY9a&HR#e+{BXqjNR!9ZW*RMGXr#2lbdG>6%{2ojs~5L_5A&8irY-y zqmRp}xha;$c#PK4&QZF{$=%t=YVsS=_Q+@sFr;c~oD%nFetBqkek24s#irga4uNOZq+ z_Hg>#tx9Pd#%Ym6rpgZqCS2)HoEKg=Ms*Ws#Goc9Ahu&uhV9F-4|9S02%`~Qh<$#i$S6a#tx61hO^a}pi zLl#c9{B#PQ5yu3J4CkwNiaJWcN48W{vIfj$>U-@PoZ}(V-o*+^eHU6aLoam~ZeYoo z@kz?j{vfk-6ca&lW*Q7-e~f>0Vgk8GAYX5y zzz&PcB)dd`d3Ws~#QkTZpFs&rmfO-=YdWI)GAS9iyD& zrJ9-l8w@hE@6#<_L^y*saj+n#9sVWrPY#@#QICh-TnQZAwgAyM++^q$2pdUEzF!+B~d*s*56a zN(%26R{6lYiJnd6-y-*ygR8AL=6j*|%^w!iJ`_Up>`Ge|)6&N))lLVW?XuOj=Q@S55?hLT{Dya=Qr<_W! zPnA8O#JYg&tGN4*ENy3K%WVKrv7wjcTdBIz{)F(x?uT|!AggvGBbdg2HYPE50zdU* zpF^sd*;_e@wpxsZFl1<$bxX|*ssxqFPN{Kb?QO&hS4`BH<-cAW^)O5KV0J3>KS+Cz zi@T9dF@j3jc6d06VAvn{xRC)VFwHd4Q9rOD+Gu~evLe{nsI&}LnwGwH(}0gY8#FS9 zO69oZ^ejyHk8FX0Xx?{B?^UT+i((-Jy26mvoUp+OkUN;08p@sVejg%v+cA^Rs?Av` z<`$LaH`byBVa1sTvb<~=9t9%X(82- zjlrul(b$n~9geh55z*v)3l2+aG~pItv13DYY z|2adV(57c4j+qa5Y?ajFc`j<_a&o9{Qc;swyK0U6vAr_1jxu2MF8^HCLn~K&7 zAarw;-rF3lLW0{s_D%#}PQJo^2*lvW&f8z--=H=sHZn2--E=QN%9QfkU5)ob%z&eT z*_0`N=V3Xt3ibE>V(w?RQ{L>9Ev?uVJpaP~W3-#cX>F-wK-xbsEO^8;Q<}?E9q{x+ z@G_#?<%>HXpXToCM!xJFWA!Op5orZ?Yh5z%!%H@(;KcdFswd?y$V{w9U-*WU#>Ykt zjQ#o;cj#|+pN_kFp^q#-9$*}hieq~Q_o1{q0xW>Ud$J`8;NVe|lT-SS2sB$^Xr&2M z?}38a9szGG<$5>2YxJ)nm8`S0tsPql0dFSak5%v=x1xSr8`9<7Qu-BXo@C+QuAhrN zYx`OL-aoe>-06NWF%if?d{UY84T{$*{QVm?S!_Q_LWEh*HUd^hvi@<+7Pty9DY{;d z?hI?QE?Vxq+B=vgBTWoGG-uF8ZeB0?RIwMDNS$@HWk; zJ_XGM#cq}@J@k{Ys+s%W((iIp7D!o)e2raLe3ksE0h_xtU@eOpOhsJBhDY>h9jj`n5RNVXfRLdQm48_l}?A z#4^Xp2h^qdDx)RF02L(}Bwfn#X-Y)ntAL{IO$llaojEFY!_i?YQ&1@RBk=P|1Ca~m zlB$0Esi-z2(48$0xBP{lm4@*J$`#C2)-?rycyleP?-rd`3HP!vKiP^xM^py1C6Ftv zEDD9NybN<{viBiitOg|E%#Yy~t`9=-DERCUt1BYK=0fkCW6em<$ zc7cI-dG4o+4Dq6ng85juM+3w2Lu>^u*BhE1R@>NB*VyioJ*xqvuiC~G&8yy|2Y)lC z-O83X)D*5Uh~OI3X(mH;G563Tu;CI@T1W=gi+_%yy%kpe1LK#T2`-C~cWMHGP77`2 zdJ^sq*y8S!$?zTvk!_iqj8kW1(_bF`)(xX{T;*MU+b3BVpS)BHC0VDuiS(z7l3^)b z2j*uT#cdzEbr&$Qjkvh0Xb3?d|o9FqntczrRfoD zAO%Ac{$d{wA$OP=h0rF2H4k-2R(Grk%L;XcZzhWlMNTI&+7ita^vP$Rv4$cVXe&aB zk(HBd6Q>wUH4I*hB@s&@vJW9`rOC&kR8GC?&PiriWGg~YixnZHc>OdT@i zoMOq~M-r5>Gs@c&M+G1-9Un7|_OqfGzM}qQ6bi%vhjoDuAjljCZsxQ%&uedTuDlJ; z;@K`HmxX{)eU?(FlQYN*W5qMyd0=m7kGlkS{7K$aFUeW^;qm zfhe|L3-wfeUE7#An(M*P%L4;RSN9k2zjGEQ1_>@n@KUkwY=mB;IS#>1C0(AM_>3o- z=ieX$Bq9Dx<%?1pWu-K83|c|bQ;n!TWi&#s5pD438U9VNAyhmQa$RAu!Yz6K-}x9n zcM^~K$e!ty$NSJRprAOUbJI%*A*wct?+fgKjOY%_+}riu#tMB&6#Bh5aa7h}2^g>_;FplX<&&lvCnD*NaL_V;Z^b00=K-)GBz zq)8R*rK!bj=P8WtFN|<*mfSSI;n|4>b#0^)$Gk_@>gqt+{+Mu}=xL3zj0PvgRmcGZ z`F2WRz@sbBdC`G-DGR-}eUP<)h#Ftt-0J`h7?pKEln8~FrSu#FfPEvYXXk_%#`FO( zcp$3W{C!yPsMZ0epK>BLK>)Jv&Fhg(qnF-OJko2P`bFXMus9)ILkEl}$$o1@|vU`TV&FExqyzbfB0XL*H!tA_pHkiO!Ms)LToobZ;b$H zrh1ac-(CoShPsWFq?qrXuYFeOZ;^WIYpWIAU%i+(mTIKGsLEEaXhevb(eY54I-bgB53f9z z_(D2rYt7jC8g{Ep0>>v(mb)o6B+Lm$zjdYa4DQ~j9g|U9B}zo^uBX@1o6g6~76v>( zd5B@K&X|rc31jAMZ5yYcHBj0cy54)-9oS%4e*TZ{(|U1<=`NTF?ZPnY{dSQ!rr8qH z$F`(XW1zqPDE}SRTdI%-9`XKRMQBS~Ns!kPUh&T|6)tPySxQ@@2G>y2$uCS1+*Ow< z^&$ZLfo^8X;KSFfYU@awpr#pFpjePp%@U{O5`UVh6vzHP=)of8cSB27-^xv1ALUaR z4)?@SN1Y9o&S5PRVs)a!>g+!2gNeY;sLWplgD_wjgZJi6FSW~6+@nzwWfu(Sd8La&6_#z zwsGb{IP3o{=u8d5*_fv=bG?TA(@1FC2?hzOe^i`MW&gKkO%0a=zuf>(F}7NXwF1Cm zFw`J%i=9Fk`xb$fzV?RHjG+36O0%W0W5=f8h3R8Pw6qG;Bdx9GtF+e{(OQ=)i$(4B@)%C4+*y%63*5}T3{;5VXLneKrM z69480vvuZO_iJ1C)t#x~XYqX(s-GZkh4*ry2^6ER5eH?upF{LJR{9 zWJ(4YRMZl+&0UKgeI0Lpy>OZ7`g{tJOnHhn*#~8cK=&b~fLnC;+h2gUPbZ{C1-d<3 z9XdEe#uw8%6;hCJFcmhO;1=MZ97P0gZU<;L813-1Hp4Ib>o192o+H_PNNj3bc?20j zP%D|-bic&)Rc4X5#1%4zI-u>mPdVh}K-wRC}?{EegEu?S(9~G4;h4?Yi*k!j| z;G>b}M6hN~Wx}Dlh_)I;bE^@{9+s)R((5aM!fc?3l6;DvYQBhYFsHAa*DPrbaQcsJ zuc=b4a5AJ?;Ga;nizH`fI}Pb%l7D^pY7XK!}kZq8>-8bCaIJZRhiMGFJoiOR}%$)}ONJ&5iW!M9%-D zed(%x{(G*DJD^hc(ux`u(zdN-Au>E%A3hS>6>Q2~x6OZE1y)?IJJpAO1q9hODv?c3 z!`x%K!+cV z9!e4~8rWI|3bD*y1eAZ7k(N=Lfe>Qmej71sk{-jrA4(|yURgucslG+ve)vXbrd{7- zIaanIv-|0fSxjJI_a!@ckKp(;^HAqd`t~lCQ|oOuvrncpt&8QnMd|^k7q$bAP0)m| zg_S4VmP8&vmiEyCPXrVDq`5L>fj( zceBwd9TSj&)DWeSIXa|!uu%e%A_~$iDJ_zcO6d2+(LAtq4O>#nWSLsjhhnu4^C$3nn|LN+=Uj16KvLAAq1-trX`Y`BIAQnR<-{F#C zBTtAXPSP7>`ALS-xJ&BlR-?N3W^>+w+puj}$sS>9hU!*Ri4PdcKTGUyxKz!k1yVIU2J5Fl0XXZD;ddCb;R#pJh^y?vs%)8YV5r}PCx6wv$y)-DtCWCeh zvayAhN0$FlwKQmE<7Oib=bc#xrBe&OblXY{ckyaE{X=?BG+QfQ)qD>COh%eo`_R~K zS zmy2qk&l{0QX-j4WFIv`&Nc2p!{{?7!rKtMuzFEw`p7RXw3*KkR`@gG_9JNDN`dhgh z&yiU*chjfMUSZyq03!l@drc)i>@|M35m4B5!SLPbyaPqy?*};$J z@}gd>K6;yFz;s*8uje1=&OIHA_V%q}jbob+lQTilR$Gr*uzKt7SyC~Sf$dqKPM(=} z=0(r?5!r8oid(2HXp6T-V;_4igH#n_+c>A zQN>i`y^7%i=qaHTtvPPy;uDlg-Nvlg2BhTW3$PT>X9$z4(h`THMJrg(5H|k%Ij!8x z9LTlHvn&ACwr7rJOtBKN@)R^a5;ttq@djhm-!{rX3TbA3X#XX@e6TVHG&L0|JbS5vs^HF@tkLaS(=+6#)A=*+{cW`~(3s!a#6qhO zXjEm@hr`Z8QtVB~0@sS7!WHiu&3jkqF25(U8w-~3OHKqS&4Ci9NT^mL1r~l;a7vck zx_iN5CekfW_)*%nm8p{Maz|UUk`iZTg?V>jEhRaW;qZTShuYMrzLGp*R8 z7iQ&epF~N?0<|;+HxgPOd`#9Gu>EM1pm;WI+eGkuQ2_WCY$G_#rw!iApfu&;qP{gu~46~A$K#tqN8Qz zK-2|)GAk%W;tmCK*U-MkD>IhYsHzuhmjnj|no(PxjomV~9JI){K_+G7g2k_cfq&uV zqbi%3ckQ0uCe-x_l=7O_8$b-D8ltX4IBJ5NT$T`i^zp>IuAU{kzC=~GD;xjaCWEK% zxGBO*pGc&H>|G=6o>aF7@y>+}>G6t(K0}q+wVn5>lL&%RLvoZ(R2RgLf%S{NPuNd) z6<4eIlNr=7UVNKx-QPau)X6#OXMSH%g*pn1EWa-o5H!_PDK~ttzUWI}p-EwEA)9$C z8tp4nJ^t`RD?IHc2GJJlI-ev4(nbTBF@<`N z_=mDtq=K+NBe>L;u)$_cIvEZ#mvDqo@Zj1|Q`aLQu`8ew_d)K#sKQ#@aqai#u2g#7 z-fW*^0(zNMYk@WZ*siWXjMDXN5wg_3NO}Uw$a8C}{Y^a$Cx6z!c;^TQ2d`n($iFzd zW=c=14*ytruG=bePtWgPU)3yUkBt&EDbbmOR4?jL>9|VkoX~h@?ogIu+Aa2B0V-|r z;7JtaJ@MZH5er!T7EtezPn(IY)o`k`xMYBt^7E(eiHj4xJZ#2$a$pHFjZe%dLr;4b zy4n`9kstX5chD$j={Tl2YzAjaW0W!0mc0^8ft85E^Qdp(JUnwU zHG|)J{s+LM4e`XeT}N1J9#oPmpPNZ`jh_A^on^$7{&aU?0ksf%o^m_t(dTE^R#WVu z-dzbaJR!tePXHJHT2A>E{|=~N2Waw1MXNP!=zVd_A8VIF-H@>ao#zGJsH0I~jYOdL zFrk?8UHizU4!kVwU)+r%`VzPBcIh!uO1m|1m1KLMavSRXOi&ccump7s$Wf1J@VPb~ z|71vN_DC9%zsh-8>s3ASwC5x3K6d};XG!+uKA_+eEDb;!Lj`u zvBhVrDya;#h3F)5yyCncImMr?aAJpjnf-p~7e~cXVoRsS5uMCdm@1t=L!yr}llqS! za~&!Z8HU&qHA=POg?0TLQK~KO&|knsYYUBCBx&*p*l!`baYC5fDN_PBRx0v6?vnLL zr8j!%}VxWv0Q7?h4kQd6ImSDI8& zZz_$H=j*H~jSN9_iX7FM0|LBV*oW`uTsn56Zmc_! zptQSryB3aeC*m}F`JO(_igKR=VMf9e(kocp2WYa0PmK1t7g734wZ$G?;pbg>xjd0O71bM-K5 zX1#?|)1UzwtXR|_+7^DANM9v6hV z;}4btD4hc7o*M6g2L~f=FPUlw9I;}*pRzADe#9gOPugO27qfbAxf(bj*oNqDx&W0j zPkb?A855YrczlkG@8aF<>uI?ui!sN1o6Yr@Ses4>mE{u0$w*r2c(yT&h}LZ7!m*cZwHY z?dsUE5>r}K8@)^<>&P&ZK^a24J{4{t3+$%PX~~lI5$Oe?v~8bG8$zX=GK(*!)@3*g zf0|MA%!(w}OF~ji+?jJ)xC~5&o6`Ti*kkJ5V~3{XvD(Fv!nDKT;mrp-3bP6^P5MW*5b*n|G|aXr(=UEyg<9?=L&nuoQQb>8oPC;>U1 z6oA+3%R0`t&$1}hZ1DM|nMrVgon+MVh=A2;%!6nC{G4>O?+2Xw--D8@;322ES^*i~I5*Y*$1RB@8E8nSar4jAMV35s_o`O;v-{S2 znx2))Q-b*+jH(@050S7&5A!A~uj@%GZ;{lU6XxLTI7JnN*NPk#rnUR6K;q65l?cze z7BdYK21R+R!Ta4x-}`Zx`QdF3K2ItR{+<~Rq2gjb#r(OB#Vl_N*JKYDJo~Bx? z4b*wP*T^;VKRF#=&U*+*h(s3@z5dKEyRZLEbDNUA5$O7p9icKXi}Pb zNO|9+li6A3W4D&AdU;WcsHY+HZ+~n^fE4u`xwVN5pcjc6Upm7Z9dbr>!l)UlF#oJk zC6ZvkEf78)GI==2lXE!L>du*u9`R)Y`Ly4`9qx#i+(WDRum;pAUA;neBYl;Rv|8wnS3 zcA=DX23yrsh10N`o}hixW#nRPmVek*eprBJ59Hdaku!+-?b?Zk*2oZFt0$bIIeF3k z7ABY|In8&s^x0Z>t%BO;Rmp$JtJm`bKJ91l7=N zX8kNT?>a_GLae35(>`R&MOShI113g9vG{;^2+UD^laQb(ggaTA>eg*}`z^fMB#>;v zhlCx7NQ9Y}vKuZr89qoT!pkK}#=<8fzL-9)j{9^x^6&e@7tzfWE zms{U`VnNSxPEjCh1^mrjk*O?sz#1Z)G9m)O_Eo@)bBw7>WgaU3(iTPgF~ocg#Qtue z+?E1(r~9!@6|sCsA#soVck;0+O{y>`A+;0`^cq|q>yAYU`_el61;4D zo1(PiQm&vA1!ayPxr%Hchm*UU@-`9M_a>cE3g;d35{{D^k%o6qgad}-qfg#%=2V2} z?%(4xb9a7uKXIW#QTn|HGT||FeoF!}JmfS}cbFnQAmi^nxbnftkE%HRrv}G_S0DWD zfw@sTPeV{UoY%)r(vc;KY)W&vGKn@*#3FXpvsRoFsVN$8L4Oa}XIe_ECKq>*mEWY*$AhIwTh$G(WJj+!$*88Jg8QtwFN z!1IX9{~r|Br{+zOq-gbn5Nr7%dePPmt8rs(-$8gg3;FL*L&od%=XtL}rb`>g!qB?IB25dPRx2Gi#Ct6Ghy8Emm{K@u zuw!m*gubNS(ksI{NA$cN%tR^*NX8!)S>~qY)%{N2zAr6TOFL<50#@2UJ3!JWccA_V zsCoOVrxn=ja^Lw{v4B-<=;v%+<6oyWWsqnaH>*(t_I?W{8jf0y#rKH(MRPd;9)>x| z15z;JzI3lpxnE6WB!Oel)!+zPE;I2JBzTqD>e$|{w(rDB|Jd0~;a@f(r(3)tx{k{WZmhIh}u0`7e}RNUQ0? ze!#dsrXoTHmR7;BA8ow~OIU5bJynl8xZZ5M?>>kUH;q8Lban@%tP=~~l|fXJEuC#QE+(jPjUAe{{m@$UCS zNoUp!?1aB(D5eWKzl|7naf|pJ(4wcZgyp3~8Ypp}MzLKHYvW;|ES7<;zU6 z`z>L>*@bco_jRKvgjLc5P@>+@6Qi7mG3KtX4R`ha%MN2)oDUc3Zbr)JW~rW7=f7*P zFS_U!u2v6r2>3dzI7+2YCAxZ7bgXpnZ!wq#O3v8Ir)2v58vZ;j74NBq8QDIqs`-Orz|m4As2*TB^?w$ z2l$fUC+V=Pm*H(@$B5I{G#;3e6&3IF+NDQ+8?(Ze)SeAp84MmF83k>OyIOg&ol@)NjNOk#Y5B*}zDDrm_s^ef zdzVNkc13BZp4y%?Pz09${mf+dyCHJhv1?*=BY3w#Y|>XK$zCJC4EALa_>43RW7y{M zr7_bS5^348Vnd7aLff=-LefTPdj(%BO?c}+q1UmG5=@~P+P8?^X~S#>knP*}^^onX zMPcqa=yEjsG~@fmJVT)dgeU&V-D60&8;2TzcfV?+ zDfx*TMHHWX*Y+=>S*GVSEz^$zr2$pFpGFm6w>LYsNUaq?)oq^tr=ONFW%?qZ{E7~~ z*I+PJdwN#N(q_vos&v3%N@NWhJXj6GY`$u2mSLSa@LCeESTEhI=$!p=_x_Avpuyn} z$9s}PHV66?p|xx#e6x&vc0m{H58`pP#zV!oX2k`+8xrsSJmEBuV1DD!?e})n?=&H~ zV^Ey+#}xMaO8^ZunU51=ke`?#M9uCLo4`6cahq1aogoNWA8h<`J~TCptLxX|Nj2R4 zoJp#$71$kZ_+0BZ;IDV&xAv_ksAn@QV3(+s)lgFMU)bqH@Ey=-KtwO}n6d}(v?kP2 z`em`wRs2KW`;%Q7yfwB-9%6T>)&5upK$k~HxQ1qd2SIfb$j6liR*otwy~0gUe|2q;W6=`I6h?Jw?M2tNF9PsERg- z?;Gy7u^ONfjDGe`5Yl+B7`4^*JvW8wvD!aFJ!P&+lQ(;)6tU1% zw;a{YjtQy<%$0VHRgWwR7C@E4`k zpNi2vpV0I`oPNmV{{VE!$HUy^j4kIWt>5qDQv?B{V~?HMDk{vqd(#xA7x|!m9TyQC zuS8}iHEU1JIab=0PRt!V28gN7=meL-V4<4qjCHFAfhx#)gD$=Pz?kPwIa730FO<7F zE0WzkIe6mL4u#gn;wAcV=PBaPfsZ9EhMU5TXgoPZ7m>n&PD%C7=Qg%>KWP{Yc*TgI zZ|z|lrr+HEOorXnRiTClLS+EN93woNGtlbo0>iw}v~Rs$v-6fbm+_(HZ~&=gcSjNH zCIyZ~TKO_~2^H-EHID4;r3d7karOvEZH$ZKBtKQZJZ8;)}M`Q#l&uV$( z~sRVJy*Y$Gub^4&I~4I7?suShURW(I_OcW9^OsI zY#~A+!WQ=+)uO6%O?~OZBK1T5(!Wvj>65FKmr#A*aSRC_mTGM~BT&i*b4l(PVA2(1 zuV`^Pw~ow(UDS&6nR!1I${yX3t$fKe*S3K>?X4awydak1(t8FhZ_kAaxCd9aBtDU& zP*Z~{+-%K6r?U?2>y2OjIJCiO`x|VQ`SpCeBS)FoODm~#jdnl-u*j}U_3SK3Na_zT z@S>KU039?}zm&kcdnZ^(RiDa9)N%7mMxrtw_AmCKFRO%?<=Q!8m8WkOFHRS&3+8# zYeSmm9p14n8sO#PxTQSXJJu#$yhhPqfb~et5>$H-B*F=L15*hmlfldio*1)A(q8<) zmV_r8T4ro{naxoy_staVDp*uxs91A>EnA`oO!@3G+gIfI84k=qku?@4HSgW{L-(!5 z3^Khbk}GQ(4CQt#JeD5;o`U!s#}AYHsvk|_Y5%nP-t_zvsjO5Mk#73OGA!3Dc2Jw1 zvYr*qaWfu%AiIv&Y`OAPq}u*VX=n(V1`8&+R{ZHE{(1JJgoD%@IW!Lx&MQchy+TaG z%Irogr|zyC8f`U7_(<<+jjQ}(-#mz8D(IMmYW_XtL||q zC8oPs>5x_$)h{G>1z85~&~bx+>Fj0@j@4Da>J=?;TR7xyOJF6*peS%Q@&3RSa=gd6 zSwE=LOavr=3oqDrQgoh;aNV5lM9}esTej)1b1EHce6Era78lt7OzLA|D9`+b^>}S# zXX}kr=dYX^>_grEkt_jB8BN1(IglU?T5*a*w_*&L{j&Q6Q$5r=c_cP{`OVjnE;JHM zr&Ko~;`wj30LJ9v5)*;cw}y8KrPKzn`ZSHK_15J0{Au@B9uZ!xh7`CNDW^aZ>dIAjr6s^z4sewXF^MwH%*5Ikn}7_-Gyr=sKDYJT z0xKD-%kWQ=vzmYhVq~*U6zxb|n8uF@X{1xF)I&W~%jwNWFe~(D<1*EA2lD<5O`cL` zG{RplvNW-kECE94KDVA|AZ7tlE#y}N#=-_+Wp^-?zyjk_o z5#Q58x-HLpr2P*-aJT3qEr06!je5?{ihaK23X#05;e<(R*l6D(i7n?I6^3_N^{s8& zH@DC=R=(*%Y%{Q#bii4H89(n<)9->Tfc_L13!q>Q*z;R2E08opD~Bm=H;(iY%Pd7o zRPB28hHLaoSIsmwqsy98C7f^Rp=zTv;XL!iL?FnTUqQt)Ur28u+Wo8vu%+7cs{v;Z z`-Vh)jNM8;5!UC)+I*MTEb=JZz;bm?=^SPCS~8v#mC=CMv?xT8oz1_B2&lk2BFSr{ z8Vgqhjh}@Oa|Er(tYGuLri0}eL;>13O^L8};7IS3sZ=E!9SeQ=Ue?jd1Rh!D7kE&J%x;qr?Z`t@^F8Ol$5O1-LUnb~ zU#L2{RHh$KPGK@9Ry*Vko8i3B;^$0^hVDP0dcW|0G>%YR2ArtcVT;eV<#1O#`7W>5 z2}wcPhPnxkGG5(s6DgPGlkh_mAC+Cw&Nx|K&vU>^mW%YI=+%}Pl3~eD(J8-Xrf}}A zVz;zY%X!2c^Zh*}-?Pw~=G8y5jRlg1=#)z<$JTAqZh8FO96506(C+-Jpr@a zwkDm#+^yM$QZ;)N+b`k@5$OK2b~SM$ZV5MR7bK|D$b;kf?Z}ioN(J2m*nFe!GhuHW zpkfsWlY;5{Qd`>C2=3eHJe>O>i65TUXmIPn;@ySZzEBHavBKC&SIIfIFizX z{m$sv!)rr~2!>U;`OPv_fW{%J9JtnRIUIiH7m>nn2!tQUBr5_-_B8SkL34BEl%na@ z_3r?BpS?Sd5V9rjO7nA;>~o9b5G2k^vW7GI*jm6sv*!lt#0sISDEKAY^1+YkD)R*F#rL^A2YA4bH$nFL@CxK*Eb!}>ht!+hCmYp2_Tn@W5! zugfSl(kD^%-J6ucj|xw%A)|JDQ1+x80lm$D@EhoD(U~-_4WEzA1mwh~!)fK-~Leg<; zBZNFU-bNKSBImw=3*V32W`)UuL`y56TmX@^cBiSa!AxyHD31>6TB?6s^wr^|)9BH7 zr5Mkt1|w(wIoZ6?->=%o*!EB_3Bdil&PSA65AVYa{HF0MW3oiStdv%@E>-alHk$FD z686;JTL2~`4g@9WWTFx|l`aV6-{SmfdiQ23J?-{ZX#Rd-pjBfoB}{H+i19ENfZwnu z#50%_I8yrum{;RP3w9+u+Mm_`HrPm+`|{9MRLD$o3cOt5I>z)_x=`WhUlx#4R$7u@ z>GFcFHS=+F4Qqe}I9O?T;8ABb_5||my^UB0;+Yh7{-jXw&UWn10`T~rp!pXKOIjY^?}9JE-_ znb+3SW6!@AlYWTQ#y3vs(MDwFMeG?&wD^@aGr*O~Txr66=uWZ}PfjnQlc%`E=tUZn zjPk_*T$o=_Mxl`m5;Kg(wkAhJ`v> zArIAvd3$YGLUye5w@x**9#HZV9GFj`ZqIPg`RE;hmjv_z!1)u6k~xdXO1`OD zCyH{aex`|R&&_$OthgqszDaz0JEabMg&yJd%CEU0iygu^>t_}Rna76?S2Xz0GQcJa z_zMCx*wsM2sL7H~<4p(Y{z@Czi~DyytXm?*Cj^qqI$kztKj9c!=!Vgf3vIZ8<*Z4& zXa`#sH}^xU04Tiz#>(wWzF!=21cGv02unnn4E|zh zd?OSPG&ySp5l)>jwmj0#7)n9u#OL13yI7KN&dn1&93Vs1okf&hQ!(1+OL~;F#S!q0 zNOjWrfP-`%8?!`=KId*NN&&s@DC0-L@@1w4qMFg#`?VF)IMaE z=d!l^q15AIgTq&!-@T>c5UI!}+eT1!i=DsZP$I~6a;pgI%>ozjp%f&}qON}y(`Hgz zae2|NsEBz^AXD6&h>i7nQGAfWxC)n>iM0J!@84DO!`056!8<(X7OjKS)`;aJw|eWG zV||Q-abD$bC(;P=LG*gFd-sLBm1BUL^>5DRbPK}u?zA8`>A-<1Kbx0-FT1sc@ z{Q|93`gb4LIaAmM)3F^WoiMfGXk@*Kd5_3|nCOO#ClAOm;w3Kxs4WNbY%-)LzJx*{hZl2}PFD3YsTGmZ=8CjY z6uxSwHaLT@p51&m4Ta2MB5eGnX~(msbaPgx`?MU?>(zF1QS95;rq&q$SKiM5Z))+l z_1a9s?F#wFSfewtzv*(fG{$gQ3(KZnRqf~)^Ht)YGRUy0(vX9tixzIZkMMV-D08L? zWNtM_Q!c3(OERDG$=ba}O|!keYs(6;$=VHB87}k7&@N;k?cfQ}jQ;2B8%F4stvR~4 zx453^Y~#E>&kR+w_FVNd8)YbP2WqZj+|gFFJd9ld`c8DVP$BLDYJ)zBIz&n~!oKr< z*g^}yp#Ed{zY{f|*8y^@4Fe%o)Q=oYDqq?RxA=7DosR5*BtisVQKW5sp3MnH^pSJm zSgb!C1oYriXeyTs867?8G((g~X9+~0%wC9+13#Un-bR#py}ToJ0Q{n78__)N;T#uJ z7l1CoYj#ru$0ewDtYtral#$+c#yx*}ndcgLn)+V)oFNA0FGFxlNV51lz89c6yA_-u z0aAD6H_Fu**Y=~vkrmRhii8Lv$Z(m3pH*&kZ+7x9_-z1jh{jdN@`PT`U*BOf%b#f0 z=r)*pW?JJbGJ9>n08t}n85M^F(%NdI zm}64bNu|2|zu#t&;&eOhM%Y-+E$sZew4#YYWzWWK-?f_SAX~QLihH_XMc zfx?sA%?8cH2MwjMvvP^1Z7<%@{rNN7k>L!nb?!;QEX3%&;rehCvD<8xCzRoumq>b} z3B@YJFsph-SB;&#En}v?>AB#`21Yj7b@HBL^C(tsI;AQxT+QQ4%U`8<=o~?v`hUy} zo}Vdf9UI8&QmdGuPM52>m90Gz*0K#!8UH`T$bU>~T5Mm+eZRDdyHySDw!@04?_1ii z&a7sT$LfAY*_zrljhI}|oualPKpfThLZf~us={}{ZN?x@HOf1@3CV^?qv%OeUuv_Z ztbp^daBh14C#!1j7d*A0#Zcz4VT-KRZWz8j`FG4-tL@dZHb^Y;ky*Av+E6|N>!1__ zelY;#1&iOie$R4%BI@470q$q3aXB>!KKi1Hc%;6mArQJJN1M@@Y`{SKu+SPg9mp@N zZ$kH2iPOSx7=QPbGp%)I<^l9&!w_R@7*#QQhLM6#Q#5YtBgO1l&>$r_D;2jLONwkN zM*8fw8ro!4HY2=BHe)4{7*%eXl%b4G(N3SOH-toKVQulYZmrSOc)56VCChMqH}j>CTG)V64!Vsd-7%>U(%qK%_&Z#grt)5KsOG&VO1x!zqLw;9XsL4;!@(xP_qL4q} z@m$J%<=toI&XRSDH8*|TCciqL78T|7_CjAzz13#U+Ir5x_*KIcl!TWNG z9jWI)Q927rj!}m#tDgkf)yhi5W!i!}H{WI`#LBgAri~0BWZhp}?k7A!TaG>$VQr7YBZX>5gs$grcdFIg4s}DMOL`=UScDB&XJB~El=I&R3}NtW ziV6ybE2T9jM-j7yLHRFdo0v?KMMWyq7}Ywe6ph@Q5=yu-FxG&*^#-jxIR#pjIXQru zXMXrgHHh6f8W&`PV2ieQS`s3GESa)pqAv;QOz@kUrvN&WY1W3>_4FcLw3nYmbPHPq7|130cU9gn`T66PhR4&)jfekVPOcOT;P_=yIEE}icOK;+FRq; zrLe`jq~ehwLxdT%h4MV1mx8==>d=hQcSbON=~eI+M|I0Mu@M}A*~-^O4Mcnf^s#nD zU~J)p#*niwRBiV}o?7+nePDLjd*3H_wD$)8n2j#AbePZXKWHIeYl!ITSE-eYD)Oei z=K!$4X1=8B+Sm)DDlO4$ZKdA(@o${w@n-Sqb@w3$qCt}7JcBB3eTDSC$6GaX0c z=L7|+?`A4!D_w%tje#S$TE2p9fZJs@0LUSfUhgL=$|B~eijLMD@>HO$-!_r^hMw(q zv~$j7^$!Q`(D%q&nTm{2K*iQ;0-@>Nb$cwUEYX?y8V^`X?jmX!&RV~`UWw?~QO z(wW8o<{h@%e+L?!QR4v?-VBy+AvMpPHh%r8$?zyYS4^SdDMp1Gvs0Wek_cH7c_rfz z0&u^ls#VB@7%I@`KOzd*e0$e+yu*`Z8@7Az{{Y#33v-QqL;$5q};%vo4UUJM#c$$|JIlB;L(r2_Pgva0T^r?C`L zK`@9kcRoYHX%4k0HV4ibboNiqi8d~dY4IAFCYT|hoz@eC;E*Q!#lwY((brBj(iX7< zD~_%yTQAtt-|EMOR`uh}MeueDP8kMr3|Y;pJe}(#jmWmleWP3f%iq!J+1xd6v_=kp zn6e_#lbikWu;Fh33i;3Qj|%;Gl?aIRE;_qkTlH3KRIt@F_DmcyL<3JMWfg08NbU?O z&)fnJ4_aJ^M6*yWg6uMi*HE{g6!1S~n=sf*&)&DZ4LMP&GLYg)UJa>|eb(tV8;#{` z#-J_Qsfjf#lAB|5Y0%28c9AGOXv$Xw(p>KPA86kDXUWmg)_SK7xE*qeJ!vVmnRV8B zZZuf&{jq7VWFLPX8@cQt+F=>;KAgdj!krG!8ZI@6o^w|0zRfTaHaeaWGse z8+jo6rmfA#eBzAoUEGSJ9ESr8EfAL{MP7oGY*aICbG+G)wcdv|5Gv7z?PXBh)D*D7sfuJPMIp!rwo|aYtaK*nxvV#*<+sV_E z8_3U4sl~++M*pg-UCeV6>0kGc>ht6i z!?gQ*J1CIIcd$kB9Q}2f!4y}x#FW%2yB4EKJioZ5!^3;=K#8L0U2L}a9r^l6S9f|r z5JzP90km3pMD2j8g!f=s=$_W^l9Y>u4$?BF09WW)n27$No3LyDI0o}VIr$Zw2*&ZC ztzLfL5iN{&Rob`m1t6lFFG@)%_ngr)Nmya|8$-lSsjea+iMUd)(U%Xv6=STqiczv! zZ2YVz{@G=$PkU+tB$*!T2}WCsII$?FD1juNDH`E;tf${?)f+Z@^ly7s^2+8DG8)xj z=4w%s%Qmp>xj4_<3D7_J__Zjkn<2 za|U{V?|pyf6LfclS+c3m2*bOd^s-)O6h)-lsg*x&N{j6YII3*0#Y+(tlKdsY#UMHu%G4VNwTa z+;Ym-I!>ywSK|epQwX(s%imY+JNx?vwYP@+$eSnt=KEH4Qd@DHygg;M)Vv2eS7)Ve zZISyUuCR_*zvY_r{*0{#r@*+LB$7uV+ouDa}huBis>lQ(;97`W#? zCvjLY#JPu5_oCjq2mhAqAM*FcMidixKvx?fx1vM4g|*Q&G0u5 z6O?ZmxU3V32F)M|@&$s~DePYG>v>N1o`>cWMHTJxPbOchyWPB+j^gaO9PnCg&&|^w zl%mIAK2xg1fI^y7($W^?v(XA*)$~~$a_Q%*S(SG|QwvQeMeTk{z28xrxT?`R3=S4$ zsqz*6Hd5fAp>9usbN^qzcn6+14)G9f>xl9m?3Cex-G3du5giVIZIX?+%@Bv!=>pZQ zl+SI_VmWytA1nCAFY}}rT+ebkX52~NH)kAHOExKFf;xrB-u!wcSPqvLc#q@&W7~`h zw}B=!i4>)BCo%oB;avHzkJC#w+0Xrak26XUR(7AhKIMt@@s`m|x7!QgyCPCx1Ay}+ zGW|xIddtqt;@>6aJ-t{t4Zl*)9K|PH_G6Eg-DxMGEB+P0$DXffzHooK8HN+hdOk{$ z{jSUI>eBew<(B#|8~QO+0+xet|5_=w_V!fIGm*AdFaHM^6RKXED?j73 zby51QMqJc(Y7Q_Ms)EtFySv)9m)5ckZamSuiZpkqZPQpWUsIjE^%Wjcv=xJb@)l&6 zDT^IJCpBC7)gD&E2Ij`P*x#JP|D=-P@65ZR->OY^QQuCJOi`rw9 z^*fn*vnj0uBXU-DQp>Z7`t|eo8#caQ{Qt8EJA$c=uQv76!(S$=*L4do|6Lr~Layt9 zvCgpfUUKoI071?K!it?V#L1&mgVH-AOtv~lNPo5@dbXMJ&^?N|K%kA+lUUeM0ogY8XR=7=~dJ8>*e~sU;V!iW&C;!cEaV*wHIQb4WtL^L0 z2z58F%mEdDN`1i^S?}E&o9Lt5Ejffbw8SHib8wTAy-s%W{PlLvTY;BlF+wlur5N(lu(~{dy~+FO zCmxtl!Dtdl6(JWXnqB;BUKR-YHC&`#pY=B(`==87g{Rv92}bG+OZoJA=l@B*@m846 z`Y7G9XDwB7+O3Lcn?awI4=r^nrKTg3VZVuSoqrYyp}+88aZ*+kJX{u3EDp0h7Z$;H zq(!%@p&**LOk0o}bo824h}8Y10SEvs2|&D(xc^#;7=@jgA^&IxX|AKDZtl>N~V>#HCTz6n+74l zyMy6;S&TUzR_tl7x;O?;qz~<`U&)j~QX}7Ezr1Iu0aL9;F&ErC&Y72d?zOmv%9xup z8}2Js%-6DP)I7A-1}#3sE?&rex1HlEzP-}5*UPI^Z$Fu~SmnLQ>FOM`g12KT7+!~w z!WsAoW+R`sGVQtiPri|&fVrm^d~5qV?2Hwe$HNGL@iOBXiv9Z%{na%zROX(Go% zAURgYw$)C~BiJL=V%4_mxz%Z*eEq;EXWZ=23WqAC37Jn>!8z=SlTxYCpY*e!DJ)3tC`Ud{91S|FX=lfD>ZRM zV{Fy4roYX$BUdjTJ^cN#$gWkO(R^1TS-6CBuCiqj{z9v7G=_`tS^X2MPe_--YId8B`TcMx0bLu6Qyt` zX;fZC$2(JZ+qw3ip;NN%cy3IiE44sB&1BSw3Zw`yw!lk`S&e7{4hg@uL@%-!QlRsF z?1Kv35ua||3E7=c;**Zi6;J8+e*df=+r;j_N9V&rrk?G>4g+RzMK5Zyn4ApiqmX*Q zdwkR#6+tOo4tR^1fFKi7rWDgrHq<4N6SPgX$@yIkO7!bUbEHaSsHXdqB5lh0`OEAk z)4FR~2ML^iJLk`7m%wvS*>0iVGq1UMXucLl6mz$w5O>fm3i44*5NQDz0%wq-HhQrv ztV^RQPZ3`UX#^H$_23Np3vWdpfTNGCI>(r^$PS>*0sA`3w!JbAr%Yq{JW30}4%SGlV-D?O=Hf8quT9P#TmBO@$t6^cz*hlgLK_!KO4 zJfzf4Z;pO4(L2WfDR(C0xus=I^cYWmW~ejN2_vL{E4G^rWIvrS-)TBFXpC9KO7Qe^ zhMb@chS4_f-)ZySc0bReb1Srpwkbj&Bs6L)*@}i=Ue^3(g%PXAlnJT}w~3KEgMk6G zgFdf<==%d(nk%(^{z+iy#6_;ogP`_`{s)l+B3ozgXpo@##kgy+{(Q#c0> zc^DoJDkhsSr@!?HUsi#kmBoHe>NvD(J3;r>D?KW!%U8f9gL=u+6WP-XvEc*-aRcRf zdwr?~16W3Q&=7VvT>wNku%0n0MauAq7L&z)fw>bY{ z9w$vbaYK}uR{!io7MorS4dIxgFF{3>@`nPhe^+NcM0ghC=(p2k z7vfh-!ZoLYOm7d3GgO|=g^=tSSi+y=t72Ff0)9kuBWvm;2D6U+3R0EcW-2fbnyD-g z>t!5|2-`oj2FGiKq+s44hw25$%x2F|zqCr2{ro_lo{nR>_?%}G0%4VIP2?p#Rkz<% z{tsXv)*tY={9}&7>eyM<$jagu_}Td6xQt=FkehWQHfqD`O}9Nu!-A+v7uxb}q1Uc$ zuzI${V^s;QTU)&U$*l+qd8}$cGEl*u$RS@6^j1=aiu|8E?5giao0{|tK3~Y)^D2q` zztb)XMKz+ERZXZ%_W(umO3VdF7-F~D6S@91oAua(GNuGC&vBw+cMR@^l6|m{Vib80 zXB@Vevy~EqPgd9frbMD-Q3}pY45YekqbXPP?i*=lr0_d`g`q}Z(R!;+no$AXqUq*) zL@`Z`t>KQ=b}iJcmt(*#FIV9gE0dAkUFgyVmI^dO!TxLA}uv`LqAI_p8aq%@-i0`VR}PwVu#CT@v6;{0JnQ*B|8#+8<4 zFhQHvzek=nSTmKHOa8niZdDLaS{r#Mb3o)D2|lDvaYnhT&PX57lRSNDb+XmYUPE@Q zsUf)q=cc)yscX#HiTXc^&ibM0_HDzXLqLh?fYCiVWt23dVK7>yV}z8XARTkWC}GlU zz~~MUrMsj=N+bmYq*N52@4NRu*e|<3_kCUGc^oY7;l&Cl)0Po?_As1`6Te3Vsj|gj zMT6qHsz}_-gBuOrLhK8t=B}j52Vw(+bgQBmnt?4#aTg_+ff!3#cfWwugam^s zwen0dPJN2xb~TX+Zl>WLxsfi49~N8_1g0@Tmyyk)@M^=>hNTH?tN)=8ce*MBHQts5 zleZE;=YSTO0!NoCoVf~jID$6wG+o!%iR_v$k3@f4+`FL>P`4A%X#453`Z}ObQMo75 zQZk7@Z<39MZ_l2Cq%v&VsG)rL8#xXB9uTWFavd0?Mo^-n{}&AU{clstpNEJ}Ev} zZZt6>x(TXHLKt!%XBGq1Zz18Yc4dfwj|fq7pI03YJBK>p{;}})A_@y*oFDM2EX>Qj ze0{vDQ6hSjRU*T>Iy`yxyTso7p^bU7RXuxn?~xruV&qB^W2I~r%yd;d_8I&?fYNwH zxx_c`#^oB~XJM2TXl19v;tF1J2g&gAfHnK_ys1Z%mEpg~(`qN6rN&XN>IAQBqfSCxX})a+rP zG8QwcW!zd%StYq&Ap+imQv~|KEuBlz&u0(xUj>{uY*yAoIC}mEsJCV$K*t}Y84Oh=tAz@amut`4>~hxMn!i5wK?is4L{ zBc-6AtE&6i32@CnSjQ(}{A@w8q!mJB%NWo6wu)!@YRRj`{7!`uNCipWiyIDt%O&4# z1Jc&BShe)F@6xJ1UVCe#C#N`VzTjCZr45>Erk+AViVLC~Jj|2Fv3=)5PQWJ)S#$Xb z0KZ>gn5rdLfQdQ34_P2rRfVM;YM|Qxy+zdBi&|Zu{p;{c9vXCU*O~1{9uFiBul9L$nziqaC z+m!d6T1z>i*X`ts(VZu5%P#O+muD~>tO3oyRcNuzSMzfRoBSQ)q7r|NyN`YlF}3z~ z>xv-q0PuL74h@gJ)#^mXT73;)#RdQQcwj_CytvE}chH`aaGF1ssGzaqH5G(wq2C^> zv4f5+rC#(1t__xc6i7^VVnq4J~8E;b{ntg zzcozB^R>qQ+M=yfT4Tzlj5^FYwOq?Q6+F8 zqfvVBaU8vA7jR-h(^->LjwmAeM}|e5%F{mst|Tan>gBFz3rrvvP1* zv}CG@Ep*ekMGpOFe4V*w>JVJxV>uG|Me$LQv_mYaHjDBj!j(+Oo3_K;PUdq>_C5C4 z8IhEX13tR2>Xi$smv%4JVQ2c63^bf=)Lt*X2E`s5XG#Q>%%|$#ImRX@gOp=ghU7Cq zPuf}e3z^|gdJb6hj^Zds8aEl{3kok*0yQ58y6cnjNh=OpcNQ4B4w*!5$4Ix|RnWbO zT~(s3U~iMDO)r1zy{FHzE#@(2{V3obmE!1fTfDK&NI>Ymo_XaHsx(_u;GF#|_HtV3 zYSoC03-iI?ySN`2Z{}c$mcx?M#LTTKLN3^RM!nX&n~%4J*I(yJk_BqGNH7Z)5a+el z%&jG^a@%TMBKQ~w7D@}J169#!$HKQxfJL>;AJ-zvJVySZD^fr90_LDg=r zC#b-v3W-uGmd8A}&r$n#Ecf3b&TJoG2e=<8h;lyGjEqmo$&CC-2vR^Rzju;Dm8fMZj=rjneW;K0uj`_2lhubelrtE-}N_ImBW5`S>>WcE5DJg1cs_Jw%7Nh+d8n_1(vF zs2)mRTJ-Ilmr)1n=S@4P%OWafzgqC@TCj#p2Q8N=7T1K?~M?mP1082rE? zGTD($s;%N&X|Rmr$O+H=4-G|Ktjpy8) z0dv1_cAUUWV%SFBS*+@ZZ2z~1)-%au%jU=$_QH-g@oEtYORIf<*gS8-hK*Ut3ezFzIZUf=pCb3-wD32ms?J0I zepS7CSe3MkfOC3>8QZm3jE^&&+)NzM z%l;(y{%IkJMe_duDrPdCsm?NAgb!GLedakv2SPx0>HvRLNXTj*C1^Av&yK?U;*=HW ztT@qN8Hc-&MQE6h$~)<@F!poM^S*+_&OS<(=S^HoC!uQB?#YdRK5KDk<(%gBdiQ39 zu8@t1*|nc?V>pJlEO5S%oT68K*pz*w?jX@Gff-x*3j)SWG#Vi=f$YugIsC4qP>NP; zjh}`F6Jy~4XC=P7YZq4Cw?n0R^sb}NR|28#aK5;}>}Hq>b+qvv8$bJvV0F98`EjBl zx}Eo`o;`5AWR z%|Wn3oa}O&9SGK5H5|hb{-_?Qm*@v0>qWGi0a*Wus*CxQ`rdjAUdzX|fa~h|M1Z`F zimIw!CGJ`i@h0~i|Lt#MLijD6zQn3K6`~OCuh8*W1o`EN7d=y@6j^%Pk2+;PmbqJ! z^ypkCE-w&xvE?J^Nl zLDJBTo5gStREWzUR3JlgE#AEO0EAx$d{b*f)lC7;^qXLb6<#KQoz<$Oxhlo2=k>y6 zov<6<(N!Ex_CRLUTD|+OFNpPocI%*IprtYRTzY0bN)#Ukn>`)lGN}7;kD518Fn`bF zfIh&}*`?&&Vcx67GhRjWbzG%m@^i|Ra zF8_&hfda!Nlco+1ZQ6o~khcHYM*6{4uAx=E#y^`4ri||>1Ql-mL3KXc7M;|g5v8f% zAbSqfG)xRi1Ob`9kJdZb>juU}z6lD;F)88ARm-pImUz}^@8jKW8Z@kRN0<*(TN~C~ z{Vl4dF>30@w<+(Bw8w^WtJKk5gN=@P+7YnC9>?45mPZ{{a(9S&i7!JJ`R|%S8kE`E zw%r#uN3LG)f7FDroP5It*LhEy_WoG;8Dj@%kkcX_ z68b0RXH9z9BIh!vF;#b~Unq4LToSm-` zn62b^nlz@gWDR^i$^of+HI74|e(%4QW6Y=*iYV8&5NfWK9^EX}8v$_PO%n6B+>`7i zhGJr;?dYV@s4B3Jbua8*`t7pMGXI8-l^dzal9vH7Sb#`2&}t?djm03`9*KK$buXZ1 z-ui8}>u2+8u$A`--|i+XiC*|=s_=3Q}*?$8DVCrdXcEy z<`0qgm?5EheUT*e>+-*F{q%gQ2l_Ky;hu12B;y zTO2TL+u6sH@zqi%H6VXIe#J7C|D#m8Mn;4Y?&%8!B9}$*HF?oQPN6kVqB5MfE=nZdzjnLz1NB=y%=+$?t@%!CkR>; zB)DA+27v<(E!UfL0hwuQmB=YPgF648CBwu4;r@+(>pyFC;UdOaB!CEn@TaLRA=0|_ zscA;B6~1;I&ni}qqp3ew;Zl+qS*vpAl5p6xbsB>nW!HD8W zl5}b}a<&&9Xkb}+X2Y8d$|A5Y<`N7ih|gUSvJZ##^=X+qj>6J<6ugM$sm1aBQ<3|S zvB^OO2*P)rYbMu{aSS|P=Po$AX$L5BR@UG^+N6rd$(rM0(4x^m$k1>nL9xn-_6wh% zIjR{s5goGED{DT6ro78rjtF}lYJf8o@N{+$@rg&ct-j+K`$c&2R5mkE4_Ox=X(XwF zEr-oa<1%HGoNM2`SqJ1JvA)gmdxcAy?5skRnZvIYcU>1v0`ngw((U@21eq(kgWY4; zhO!go!RZ=+{ntX#s;Y-u9!WDI3d;9-9Em;>HF#yEo5S_A<}I1QcGJiXQOnlqK?*a3 z4UsHR)|7g=S~^_X=e_k;XU%E)b*SIN0QsKApFrO{#1KV^oHN~5m^XhK(!bY z=2i`~S5Wx(s^RrStUkr#L<7EzNq+mW$+@hRVYZB1KH4t^No1M*rcKkHwWS$esbB^* zS77LOyoDf>BGJ0X$zndvZ5|?*&6Bg*1nRt4XQ+-?q^I+djWMm>T596qOLRFi_AG~( z*uqYAM3W)H`m|d+`~L+aDq}w#7|Hx)6ImC_08dMJC49_&(tMf6zoC2d>bc+%XxuR1 z%y@iSR<73z(7j#4^2Ww8IKG}+q26uQZZWZ+v`HMdYcP~9-C}rg!S;jlHcG``>;zzkgE&T5) zNH=o@Q_M;W(eb9PRv`Lhj!Rhg^AVEkpE%DZHRqsjBJ_84MbU+S{vll_JO7(rE#o8_ z9GU73oG&KBeTW)^a)Hq^+X>)Pza>YS1$lgktKW4$XT3&(pijyKH!g0 zzrrEh0%`b;&Fd0s^8P6=eSPpIt!vgUE497?-hHXAc5AU$EbR1hBT1;}pt@#_ZNn($ zfGgb8v|j0_nQsP(hKY=#JS-{b?VIQ;NM_J9!V1h3R=F{`PaG){kI@lB1!;8Ta>rbM zuc2YwXY!rpDjnzm=4QJbEgHPCRTL+>Q7TA;I`sa<*!@e8qsIxMZRd z-9Y{SReiYDi`Yv^txrJlp11S~k!F-X$pE?EHrqvgC38X7oY%w&UWtE0Smhb5n%n4n zo&psV99nuJ22A0;l0%90^S|nu?3>s*Hla;xHXZxCi%n3{+;TlXfxjv}OVZrT^_)hX zSM<7g^n|vJb8dN$3RA*y7l>zxkpyG;$K%9Ceyc2@DUSvS z5ZHH6CWW1$BTV3Z7eSt1003d9H-Y!-8Vg|g` z&*Jv~T+6%nn>`#T)|Gw2i__go0@6<1>}hcPCfp(T2{&thgDK8fRegya)iTqyKK(@) z_~V|CFvNKIF5n1q#rz$8+x-Vs`(U&G|7{=1`$xzuffkwuhN)bDrSP;rKGYeX{cFNs zMn~6T{ON1X?iyI0ruDdL_?bDBZZGbuDKgIrJ^^(`Qi>%DUC2rC3X{pi76u_6zXGRk zE;%`jiaawZ&ac#OL&wQ%c(Ph{e4X8_eghqeFxxuYJ=fr`-a%yo4G64eK_;}xiu`P^ zRM75)gCFej>?m(#5dv!0Zs}B%<>}0FU-eXW=Mp9(jJO{a_c4Et@(u@n*@sY?1gy~3 z(;+d{>km*RC$MDDrS!sk2>-Mb`~3yw0CW_EV)dQ4mDwQ6p-)Uw0E&#usyEi|tbqp$ z#Bs8jx1&dzy=Nd1JekmQrCxh%RndCZNyI4|m_I_Lx(UXSwDn)=w@oisKW$T9|tg+yBpQ*U?F z`wWtd+CASWOIQCJfa-M~@1$St416nP*4hmD%9o*F?de!{c>hkp1#Lxo?& z^#m%mLC8#job?P9ddFequi*eJBe($UhN0h zS@iL0c*uAVohy>?kVdAH<5+m)t_j2v9lyZ08oSag|L#@WSJ+5kvLGtWR?jG2hqQUS zyY#Bc8ExJ0VrAXD^O2oDOPLp-udVHS0M-Ctpb5p}C}RX;e|GNJD>N1c*$De@=GJ=N z3~OV|LWnQU(RKq}9YkUal?noXXj^3H-1h3y5<>u$mPuM|zv9Cix(z>0fX+s=#|c|f zD^`(ByUtYCa-+dlwU2}|uxaWnS^CA0P*G=_bxCBlzmPH#=kds(E#_oe+9BO{4BsnS zm|L*#J{s}u*%!Bp;sexy`o)MGWHwc2X;UR7q;ZH=7>)3dP|hOcK< zyqF5|1ODqXgq2vJ($8PD(h~Ff4p+m5;`af1k8xjXEG7Lu)2Tguq9Y@Y`}ePAi1KHx z-lVd1m~%2K2Pk4*q~&-Le6EqWZc0a`sp`#c5k%jk+hA*+a?nKB%Y%XC40HPgqH2v#uFc2!YRae{9$T^CA9E3M_+rR~%M{Z-5J z?#o-teGKXN64joOx8j%pYfgri+4TLvA}Jaweon8Nvci{%nukFovww#FdAYnZ`y!L8 zmX!ZsJA+Q2kF?QQEUs{vnwBqj~ybe5FDN3T(c1@7_`whj0h*C zuZ`)u>_U{Y$~C^9^cuOn<~YJKgQl{4cetS}cmY9xiv`tq}}>SqOIY785dN>|58frK!o zI=-K$wS-%e$?z~n`$9|MK}9E2p<^Mb2#aDh8FwHAR*(YSPOBi3^AULeM5MIaQ34=@ zH|P#X6hfgyNR(|Xo5z6TWI$LRZx#cTezQRE_5=#8YAqUdXNZ`Wy1bX35ZyLp^_pFa zhrOn*<^1v@3OUs5^YqCznNpij#v4^nQr;atRJyL)v)7qk2f+#F^QCT4LqOutmWQ=( z$FuUif=hQ5q?Yq)#G=skuVoH~Q{n2wgnrh64MCM{6rInK+%!(DRvNmGZ)YM1@}zCd z;$?)<7l}J$+1Rx>3X+g{zd^L$sSbTkOUFUTGvrdzv{s)-iuQK_3Q2Y0RewIqoy62Sr!Le?CYr)r;iMBc~!H| zE5%~`F|nuX*i2S_(3jCtob*(w@XY!j3swj84wpdz_iEp+d!<!j)_QXeU(QNkyZ>9j9UAWe(g9`na76yO|DeG zYqs_WFJ9ulCsdJD+$A_?>_mLbaBYo(#HQW^kSHiqPZZV{0_> z)%Z>F&9G?FNO&iRwA?#rE>6@&tIN-3rSYZFqTog>^aiF%FPbJRw;FIHd>;=}wQ6Uh z?*jkF0z#$l{3s2TMRSWB8mCq0jz(|P?C3_FBREwKxX71}apcnT zYw#Q)8mRrkgFR{RubnR@yD>#1bQ3z}7Fl zR+GKBOzl+YfnENzE9jqa1Puks%^n%3ElQ6B z9iogp=imW@j>Qm!dC_{nq80qegj$Pn^o2#)qQMv<77#~*cg~h;X;@Q0b1qiXg5&#k z z$-Pw@J|;>^6C{C>H3WQHRbtmnTlaCxO&$7W9o}?m#EVF+%!v7L{GgGueHu9r?8@Sa zzkk~(Ki?s~jrqDd=%pu_$*#6E_QZ65vh&UblcGG%Jm)hTT}Q~d6^qOT(TrpZU_Cam zF4oi|L82EVMsA;jEzjSg4>-J`&O&jcKL~VU4?$>iza?k*waEdeQK*f(PWuWWBtlV*M!_CXqIu zLq$Zmug+{ckQk^5$OS#=aT%c--Y#rr(hwe%-}S zHh!}LagvS23Ni_fD)RMGONfo{Ls}ZAR0+qjBl)gL!bmRv{TQbr@ucHP(dp#)++_*l30*BiS-L|XNvpNpn#-BV6Wn%PMkBHmbJZ1rkcM6U zLb&L?0MKe=_IPR8B<24A+m>YA706mTrlDw3Y-~YGkVOj4G1`G-{TxPa!A*rs{8i;U z>4wG8GRFmd7qR5*BZ4S3*<7sTnYH4V>wShL^I+55!g6|kO3Q91mDi%_OI_cHM6UZR z3r#ahDt&f>N9|2x0=u88m3*>zT(hCbxY1(3{V>Rw2#^)w2#KOh;-Vf@=cc8Qm% zT=#pFg13aNG3n2i5{h8xw|2=!QQ!AtWtv^x06YFQXVf7RWiwE_wpRW4MDy60`&ie| zztdPPYnftB+FaF_Y@(Vrw^NM2dOm7ct3{tpizu>$;BLKFJ*Hy*EF>Fv9-2^Q-qDx_ z%$c%~us^TdCU%R>$nuJ5s8Gn_M{Li@B<=O*+fSYfcCWZX2Io85F1v%KJ@~!#|1OI| z2jR5~Zhu#1i3`A;`BtS6AtvWSftsD5V#uNb@%LWgzN4%o0Z|)}>zYC|N_#;7bYtv* znpY2}I<|%K*$ijtcBvx2C{Kj3=?RSgG%Fld82B@Xkf>Aw3N{AJG!kdN0jAX!Sm^_hfs zl-#k4`=y?InRz3s(&}S8i`&mIm{=j@*7>&kFdV72(KIwJLfA^e_bU ztYP!gh<9c8n<(B^VgUt6y2}Q+g6FYA|-FVV%eArvsqPK+NHsnxXvevwbJM^T@^O1_17WP;%i-H z`B8hL^A%i@WSPnqPXxJvAUiVWK)Tw@aE@NDZJ`Wr-_am!D#JQt_uQh=kbEQSCD;OH z{5l~8>&Ggy*Hw3%GPc2c0&uzWwldE#Q-+m+q_3`nmRX8uL1xFqd$R zkxc{W?i;Gj${gXR{2hUTckytndL3ifYQ%z2VBO%P2S1k-C$#RftH3K4{-w35NwCLd z-De^nP&sQNljJReV zxTWLtVnLCL=pl<$C)5sWJvI9H&It&uknL@bTUQq>; z$c1;EuIqY0O-5kBLrG*r_bhJ-c^ts&a%T9N&e$?q`)=!{QrILXm0YRNk6NxqAOzaC zCE0}=k`lf8Pczr@l#nWvH8d|mg;JNU7_T{dFcmake^BUNAo%F6oq9o9II=|qG~=DV z$m4CFsLn9+e(4(%ZezdlUOL{@!%VqlA!}Dsf@ux52gk zHEqU%4}BH+u@Z(>e5*bGAr9f(d4gkO)1obnNQ>@@t-te(WC}lhhX_Jg^!}rqUj#7S zK_-zDC_F0!twd=OII64JjKG9#luPqg@Tzd5=M6?r1s=MOqQQ~1qBKqG<*=HbBwi%@ z*@8K=0Dl6N-0&7E1X}8xPCXoKXZPP0v%?S8(TJnqt2IBx6Whg=)wp+Ye)KXdG73`0 zN;;E>4af$*%dA4>x~|bR*zWtnyxg<4u{(r@)k%#cDVfqmtQxjSyBqvT1MH-ZtBA6N z=eFra97_5AjVphxnHnoB<^9~!8Aq+Kq^MJHIS!^Q!?hWFc3|6mt{cYfdfn*oK1Rir zvG7xF*ob7SLk&PTylzokoSwt5e|;~Nv@q*yvc-wnukmSv{70dv!{(`Cd|To7evOjl zda*Gl9W$Foq0rw5&*t^ZE5dfC`DI&T;N2ZtY`No@%et;5r(T42Q^;0K=?{`Bdz>#f zT;t}Y66>R2ex9I0e-Rd4mnSwQuUYm|Aan}fL-F~NS*B3M?II@Oo7R5N@p6pjXwwBt zaf#7lt@nQAR()1DS%>lh<06kyuG@ip^vtgbIGTj6N6RIbAkMNA!(Tx562u2((IyW9 z3y(fikE#jeWzKUO<3HehkGu4X)1%M+g4&~cco|{>NHW%?Rfe$22r6r}f2Q})-CQ*q`VSGZTsHZKO44SCg?8!iMMEc0g z0;&sJ2Y(2)u%al0lZKFFAT1ZRU&O^@^wUI{);5QE_L7uo-_@NI#d9y4{^V0*+h`hX z7Yo|3nYbU&x5Haj0qc0Cj?h@|eObgeBA^V4mVa_5#ZQm^(|o;zH8=PV+jNEH#It8| ztgeBUh#uRaBVan%@~gFT>s=SbUc1QO6;lHp-u?dp#7Gabl(06tbhwadE7VKrkmmi$ z_UHQ1euyr)@AO$th>HSZG%RgW*mo_+4D;TnY*dk`v!5+4*PHkyH_zP*((Na+K!Pecoj^39A>a1c|o=%{Ldl8xJW~FXuPTwilW% zjFu0h`>J<v~22*t?&`mbB_?i~* zZYgbuv9FKdR(5;BTgdD+2EtkKTtv4k(I3dw!C9Ehz*mIaCjZDq9rY)bIU=KAB7cL_ zgu*C=y%EUb(;qWzA|s=W0{ACdqc2zS>k9d6sFVwt=wAk}cWp+t1HEDqNuNfLt~oxR zQRw{JkujCv>dE^%Wkkb7qDSDA{vJ}QR#w7(M8qySCGbET+5Y&rh9_OijlTfd_kR5@=x>` z7T{w;#N+N|FSnTzmISL5%%i)_U>uxxq<{{v`DyM*s^c@zCp_%IyFA?ZHmL8voLZsj z3kg%ge>p>s2LInl??7y!_bH-j} z251kRg zd6XDvLEc6pY|AN3AU7022s}ya=>Gr>ahQ=~1$Wk=Z&K_@)hG7+WW&LsKPTnrsxozg zq>_@XQr{AWy&eSHt#5X+sz*g2+6H#`6l<(za{!3`F|uBL?SaR{x>T5dZF-OyH}}pm z-fdt%lUb0Ms2Fgr*4T)ap)amSgJSfB+V0!uEt~%9=>l$)yXX00d zY#t|pSE%#Ous}?_%^b?Qw&&&=AiSIBLIFvFvnH7=DPGB$*=4D)W#g5pSms4n)Lf0`nXwK*^Vuu_xJ9!r1was5MPfk3I;_Yb zOhU!7<<(}U%&aq2BVFv>*zTaNxC0!sqyGe>st;B8_}`Wl@Ns$_q{q!Fp*4o$c`_i1=uisV-=%BQb@toy<0Iy{UuIf!M@qwo_ z*)8}u=?@qf$}}2+aC@S73t5}XFArOr6p9(_l9wuA5%pp3Nnfd{l~772*32R~-aD%Q zvGV!MkhL%KH`9085InIgY?0&S3EwY)zn@uEA}pBa2JQr){qAom$ z$;ZGBWvf(M(8CZIFfKlJ7MaO2KFOe3BYtqsvNbiB{=v>DR04p{P$UELCfI`Mw$QYV zEU|sMpkX^5hIH$q_yC-8I_e=qzdpNebUP2)lxwP+Lj-^^^o0@ue+KD8RUjfbuq)@O zvGCrOGcJU1vfrH&eI6>=81Zh)cWgVwedX_C4XR#4c`f+XMA(ih65&3ZXLD(cWf}S1 zjJ^<|d0fbhF&ONszo$$7yh`-MX$+4-K*f|TIPN(mX>l2Z+{wlzJ$h5@WhLAGI6Wwf zLgC(nyxpHbm!NU3oM!r)4V}0>Yps3yA&H&Et7_N4hL2hJoZE(Wv6<>=XL(XR9R(8Y! zEPPirf0p8s2{+Q%+)x+F0?^5^g=5J8t_1-JNr%8j*h$MA(u*y1JfA*L__Wc6O_4%S6YkE~u#7WlJT zyY0L2XpbY@-l=lq5OI)K)vU@Oas|9rV)v6qJGX5gmW)|hQpJdB3JL+U<#iLZIqybv zP>)Ds%b5Kk#NZ7jE=0hVF1+vH#!O3U-Gt_w@`BXbjGFn`a#bp&%(@4jdj)7v8Ib;2 zZZ54j5b5&k_W>8)2$Ln_2^`CkO{autn^j@pnKh-^8BXRs2c^TLy~EBTWy#L^KXD+w zsslJA1~#^ji=?*w@YZy>kmOWkkSxwq;(d86H3^t#ad-MgQdR}nVlCWb685 z7P((D$>k7QE0B!TO+y_}QDXF0rd)4eyxk{OYp!u_ROt+&HMvsWN@#fa3Kv zcBSdkvq5&!kdb%S^@j_m{#JFHDaCgp4FeT)FlX8|>3e8oba|p9(zt!WHQ+e11wF_2 za#HSpfcKuYiHhafapJ}$+{HOXUV$Qgp$!$YtSBv0ZVP&V09idtd2EK=OFyK1)d32i zDdSaH^4o&F5ie2tcz$83*WmPI;g_Q|duge6%S*@=htk3f=0TPGwCzR_@pj!|)7rMi zTVi)2_pRxbZHco@l@55zTEp{=88|>+^np;|yaa_&Ikugfw{AS+NzOO}%R(mr0=03@ zNBcfG`2JINycp#@+~6=S+YQbW?6nwqaECHOSm^BhiS<(Np-w{HkT+T9R3L>Zu!Zs_ z2V=rILVQhO3W6}&I7`Pk;hm>nspi<4=^)?LpWLO5IwVIjru(b+akd>>~yXl#dNV371w2b^Wf zwPU&hmzhMnMh9=v=1!m=nSY_et5h)E`|;sPP7;OD~vn(Hx__GBG|UOx_N#GXUH? zk<8O3Y;w0RuY60M8TzVnhZ5ajsRD&Zlg zznS#qZLhbIuO!sX34JxJEiU0ZCfbv}=imoN={qz;X~6mct?$Dxj<(f z)o}S9uZY)-+1)RhSFNH07(+Ga%xLQ&Y5*ZvnsL0TaGyZ zEJbGY4A_;ELC7GVJq_@cTJHUy7ITH6ICEh>=qLyMBj>K&5~L3;zcqh4bTlFttHBmo;bIGDol8Q`i%1U8F$0*5$QJ7DQb|Tma|Lkx0sBVV75U&|X*;j`^VEmt26dkS0mnvk z|0>mG;n}S*G9up#(6Rl%JGHw~V1_nnT+$?~D5j9J)UsLlud;io43LUoVbDT7_XnFd z(ai2E9BIMgiY|l`n385$)|sTJfD|}xqlfMMnVAd_&+O$AsWC#gm9$^xPPcr%!)d<| z>T?%p+Ht1gLec18xh)la#fRMqE+aX#Ta9#OXrCO|b&&Z$cUSHD zZ(IIU4v612m=e43#J3EhCW0VP9qSUaCKz~@)cr-eSEvn{icZ_=n&E8#h^s8T$!#~5%5hZ za{dm_Z+E}}OIg5dJ=7tXOlUrna7HA4mk-dPeZkqf^I;&?DoL(oOg^c?r9q$Yt5AU! zy?PNH;!&m%?cW=@Ks#Ad(5w?b!5 z+2@*`I+VYjseuu4pvRSC5PF8#Wd#RWk>-IcdRDHhA1fR*p9+hBH!HZZ{rR6H*DF1k z*l$2GhGV2gRlQ|Cr)>SKzh6Bsa2l6C9cx&a-p+z+MCzn#CCxS(oCe$Lv@YEKGUNDd z;b5F{`OHacA;f#`fK>Qo%X%G1va`6nSh2V>H0hb~szJw=42^AkU~VO4?3XUowdVt- zZDx1fuB{;^tSeK!HNR(;4>Twhw^`sPHH-7h>&CfQxsYMg56gyyRjf5eL{uy-e?H2U ziJ=uH9{pg8QF-cZV(^Fq>jkZ{xcj8dhT+wqbW-jcj^p{@v5toG#oz|2fpaI>^vYgJ z@F*L_k#~C4Pz31Z*Ed$=lM?oY)|v$ueZ#JYW0`GBI`~szx1lZ&$V2Om@FMr4VX>o}jc`^w$HS2l7ZkIzH!aFLthn$TXMO9N!Q+ z**w*MiBQC{r9)hQv>6e0xg2{REKNuBa6bTDSB^ClX{`D~&(bR^6TyxEz}HySGy|!R z3=d(W&EJ&g#cIa)YKQtxw+R0Ouw_qe2nR~lD0D#FbsYJ9dMGJcS0do+0QYXG{{d=2 z|3}eTI5gS5ZFqF20|$&oVjxmOTDluH8YN`|kuh5FB?NK8q+^7{hz*!@qkz&418I>I z5Rg()-}m?J`y-y`zVGY2&f|#f7*UDC_jR4>o3kd5OwnoVQ9b_i9_p)U5Lf>paV0NE zZ?ClzUrxK_sSOb(sn#h9U2xzt=v-bY=%;m-Eqtu^Fj zglAj^rd6nP$`LrUusWCSY|@rs#;o+^T@GK9>IBI5XBGKWnqw!$*%J4+QtT+^N~&R~lBn;7Fl_`yX)p+Dp$|=dm zoX-Qf+v}?2m%X!9$s8M1L*6ygwx&~%i_hUZb}%G}DRa%$K9t4al$*4BCq>J>_*40F zcq~FR90lS5)JU?qf`U5URhV;}8+oq3JpPP_6-5v>aB^V&ASH&!D~Q+?U0l{S$c36D z{(KQ5?pP4uoq8^92%z$~ zj;FSaxaTu3dxPHWv;Io))UC>9!{_dI)N1^mwTeiAptR)VF(+2$OeE-0q_LY|KtaDg(eVUnrH zg*{ag-FqrM*7OmemlLpWI8rOio`*r;J(Z|2$G}{|Idz<` zbrxJo%s_dMN-qV!cJaSDyq|flGUbd~Aqor(@6a{>a`axi(b-^S-bmbjBspd#TH-qq zWef3*WV^U9SEB!RTgk|0BpBiBSD6#Bg9BHjVk+A#|2^a=61YWhcgJH(&t`rvM9967 zP3!wfh|Jy0z?l^2=PdUhY6tKYhrCboQHplb8ETj6SGP7fudA(;yZaAkRf|f>4lRc7 zF8GF7aDS5Zm>DgM_xb!%|1*x*=d9SPg@Yj*If?2$TiHUaNV_6sJXEC-QGW!NQDa?R zE5$6*^W;qa>V{>jL#=r?`8$QRYr~@FB&bU$IvI#AJ+jV!Ihg*M`EHdF5701g`#liG z*Gf3+1(T+XULWYG0JdTeln|Yz{D9NHQjCFNJj?hD zw|9Qp4AdQunb#l12Ufq!o3_=Z?l=sXHpVs@5C4^T+k)4HToUVR)~rT@TMGh%&Gy>F z+Nq3K?bf;Pfp~e2jprLCK2cKjPW={e%jPx;v+cFKR zbcnZF0L{;GAMQ8J+?03A&xJzto|&y*Q<)Db${#=XQQN2dw3$;Rm(Ga_98ieyg?nwv z?}mXNKul+;*fYb$ES4CujZ`2NsC(Q!w z)kO^U444EYY`?mt;lrs3>bQIICaSzV+xwB7fS~rF~&n!maj`bwM*o zg3;>VN!dhW&(cY1%@?*~OERBOS0ul3v@$pI#YUIFT;Wdo#{nrz^uMRbLFeVqd*07l z>#So^oGWCo$g$UojT;r`?xJG(<%a5eb+35a0IKm*NFxN*ze{~55MX{{0%YZaQ?zs1 zJTpCABU#5gQ*$$nFfepz3NA@5YRI_Y%6YtRvve<_lS-gobSbI)v(hQxY*1EAY69pu z#dC{6YIiGL+97urL_r9qHor3wHn55!>-ZcT*fW9@2Cc?TIh%{XJCp<* zkdXfOen|IxY9`bbjHf` zMJIv4ikowSFUwL@>?MjhSW2v5io7Q92duFSX#0t|$L9+=e)}QBpIm#kaC>(wf=yf% zu9PK!J~(!iO6puM{!kgHA~!Z%!QQf5!5YUi45l=TtX+=_s3iDDU;WIZ{lPPbw3Rh} zmNWf9XjA~Va>oEyPHuajWBMH1%DCOD#ZT$huDqi&ug6urJ^kfaE6J`r=<%{ML{X5< z23*^apiUICZdK~gW`N4Ij3YyhW$kCE-(6+g+^Dy3VvL5eF5ddJ<+D+r!d%{X>bRAK zhGYKr>uF0HDFxaBGfkk85md5{Kh*7ZFa915h&rz533XP9S=0^&z;yeG`JX?4nTv0a zH{S%a=g>{B_Z>of-5)i{jFh=&*U%jQ^QPA_K40~T!!6jO&b~qaAUh5R=EdIylqWnT!SObhX zT2W4HXS;+JMziZtVzQKO1(X#yDQW1Nf0sby2uSObVl-C+*$j}fqb}^a+)yZjb~OtJ z3LC`Uuik}!%ujq=3lDmf1^3iDk3(-X-8D`HV|(^7@8oHNsIO>*)BO8Z9neBW3n^>r zLr62^E;)q$WWD!rB8YJ!#?`8@fTFMkTmo(eR_dMGP}-^kTx-GENNsgz=}q= zdxXc@$XkI7EGVXl4$aYNElp*r8|}y1E+Cmgdx?`=1V&b;Pf)}Ozh+8y;`2>mWZ7d; zR>;+ii-=joc?E;;6hTR%RYL%ASEOFr3hnB#xC6j_eY6IKe~;AqJ<}{NN`UZak^2&4 zebGur-o4UQiAG96PahlI20>>~^vW9;I~?PYE+f12ByfH%4s4B(QP$hX0i?kWdV}%- zeDl9NpYp!eW)EzJZ&1Ben9#e^>L3#YWQP)VYm(A^J*8Gk=99l2O%)QRQ47F#` zU}muQW45&=obv$QwVGUgJTj<_tX-)@-LcT3dh{uQ)a7Qh}@vamy!Lm`NPzdx~kIm2)rMJ&5ukkR&O)>4{$YiT>y2MplFlLCnzGrHwbU5bl1Y6m&BV}nC@Zx7De%ts%{MWh znoN6^wqM#5aw6_WZ^o$sGX=-rf>B*Y6258w1Bl+9p_wBciay3izCe}&?tmnIR_U?0 zJG+ic0=0Zo!>6LE#Z0Ke(=%;DdJ>}c2xV1fw`=cZ5|O@far0*C-%L0TTpK z{TU!BM7VP*y%4r@e8|Cn{S~mBX{1*cUo!%;bO-umd<)bz)9b6fOCevPi$DHHUyJ?A zydnTzxGOiPy3pUxBf0B01)&A7{-aRhl*~@RXJy?G8oKNfKy>Lrn(-< z#tIMt3IcpI0MiV>DCx9hNOMa~;v)Kg*nbRH1DXh+Uz-=^dHEU2JExKY?BZMYU%OgS z;3uR2KdJpmO1YOac2{d5P9Q)+xL$%;KUwztXRX9HRO>T`K{EtZsP2Z6hA%T#Md}$> z{u5Zumt5#|*6w51lBJ-B&Y$19|19-Y$O@tX@HvOJY}v6NznA40!}l;U^XS*VE);|S zL2!1pd*Nv}X}huzUs%62aWgrL61RAB3V3uyvPv!q%BG3PzoS#JM$RrYTMsrB)gD0H zWW<>4Si~8B#D93QAX~zh5yNhb{9FAHS1@$~ZweNk*!lO1X)J53+551e&R^5duIr2K z^&9W~-&jC+S#GvH%PCjLaKESJK%w=(%iFx4Iltry zSXNcn*FGf4!yk%YjMgezBw7cup5yn*6h^tOlVqz@3aW3!b$2h+;MW$ifW0qk?MC#D z>}QD&^@93CqUudwhAPMkTcJb&i({EdmXw!{N+;pb`Tp(!T%UV+cpv5vnM;bQMaW1C zH`FTo3~=$$GEd?b)?bD31aJAP>9k~7(;{Pu5(wJa+^>&5m0ZCp#&YjPLT|0%M~lvE zuM6`KbpjgOf{Y#wQIjg%HkGDMAtP1ar^Xuw z35zHFh4g$=Y)y{+v(WxIRpEZH1`JU#hNa((9*&{MK6G!m(Ko2>HBx7#wDUTrBU}x- zGYJT^rg0yhHeHxlWZlDSc1PIMmia?(p(77#p9Qn*BSF`)O}zJxAJ#i zs^p&WKKd4Fh3uyXXraxwW4QDJOoz4|{!LagHbx#A18BhWn3;!@1k+^^Z93`&G&bi6 zmgL4%UhHi&v}6Um;*JMO3`UocmMRuQrcrP z3q4?*zoL;$)m|LX{$eq!ta7>)0NLS0Pa_Xo1RWL5@mkoNv3Lg~as4mpn~8R67qa{g zHD6>a$d5==g2=!2pZF?~<0@Xxe+Rliq|i>#TOCw$W4JLE~Q1`io7gWVJ za%$%jn73Dm*>B~$>&_~aKr%yTBm~MwZtN_QbE|bk|Fnq|CzMS-iow1>-c5A0Kf!HI4w)-Rw-48aWbkKZQIr21lB$PW=UkRi1KGAp6lXXe=DA#0-u zhhNst{Sb?P1Ldv2hM#-vJB}PC*O1z&enc4yyZh|&i^+~Oh-SZjrHHPb0ar|Pp4(}#EU1qT4BTH{d0afl7_IA z%%D;2X%X13Ohc}B$7^cR6c|LHv0sBE@uUE%+^+C($6=31s;kmkT`sJI*e;9!zm1J6fkN$g+ z$JSPZ5&PKX+7JSErtC19P`|#ml9pzJXeBPqls5aLUP6AtAHrg+(Dxe_Rn43! z-v_rYIJTYSmNnt>h3jEMY+3`L2?o;4p>@5n2O>uI*Y5H00k=+fbEHm$AOeB~g&~YP zA@HVCAlopwBrtT7fr=aw1%3TAKXw0<`G&yK&eaQ1#S%8(!Jo;S>=OJ1}qfp{M-QKyyCnEH7aANGE%f)2X) zQ%KyEA$n5*x?@@DetT_~Pq;;#WYQO&6D2xeBHPgU6|E4_Rn-N%66AzSC0OyN8il2t z0a#53)a8ARfr)o)S###M%vAkRY))m|OzU}$#z zW5r~HvBkePc4%oQ75v_Jo9qNx)wC?t+q>)^vqnHX(UNrE--px7QuCQUeOMVN^HI9?=jSYY)s(ll zBz92L;ab-&e+S@MY1N^xvziAaA%)Qicdc=bSBUgtwO}Od;*$P4WjHXqRMOWg1CD18kPeu{SRmtesRwZh4HZ)6d?f97yyyI2q4*x<4Sv8i} z+!q0!H>$F4dHhA&D9~V)3|E#(ezaZ-->~ZAf;%kDreRD;0wCh~9!q(j*Zn;(`5-|X zS$}dR&9Uw<$ePqyi-=56cH^1?Q_H3&Z_*D2Ew9DLgb!{RT` z+hdppC5>)J3fac(rN+$u^2W*lo_k|k4h{NB>Fx9m5sJEf7`wUj%Su6Ms%=ntyb-ko z*6HO>nf@QpS;X%d2)9Avsrv#TJ(SJxfWSXbfCPWNWIVkaXF$!Sexi2dZuPE0f`K+u zr`Hl~S#u*evmgM|Q-8a}BD4sc0)C+56(`q-^R zVBYHLJ97aGc~L<0b6jX_?d)Gs-=Jff{{e2GU3G@+JgloeSSD|9av1Rh=y#3)$@iqM z2+4{V9lxEEzS z*4O<|>(n?72+`xC@3?a#AbIL>+y5&`E^3ZXU0TP9(A3V$hcd`Lnb0r8vdP~VwFiS% ztW_WDjZ>DRx9MxFf`&f-KMJ%NcD$eCB$P&p+@z6Vs&yxN;-{=nn41K~k)&oNBxfrZaTLpWbojs(M>4;$?ytUw58x&JqX z&?jPl(7{!d>KK0eo7d>4$H93?b_f^hDYjT8Fb%~<3NL&IIi6vZ_cEqUgMtueUQ@gFy>##oc<|a z?3yH5x}(x$?y42ES3g9%{BjuZ?_ncHW@A@Z+?x%& zQYxI3B;kK8P*cmr+mbbzxM%z&>GsG+s%@$96PXP2w#-t8PB6NJ%n{O^y~h2cB9JRt zsMT{$d!|ReBTJojq2R%jz}9SqrTtdZGa6Z+_abDaEk}`*^M4j^Q@u*Nrhp9{S@js& z*bH^uAN=7@7(3UYvW+>Hg%2fXlc%6VWW=vgf*oX*&3UgiP0f8^NmzlW@BRvCJVNBt+ZKU0bWzZO zUvI5>+v&(p>kZ%#`QPA2owB#WVghsgjwZe8?x_uiX&|50#%Ds@psDQTBb;}+7VF#< zSM6LnoU@@;qVUis>|}R1nbeuh{W%P7w8|wTSPM6M+PYoo=T0M0`NF_uvKY9Cr#-Pn zFm8+CeOZKgZU(nf=IFLwO^EZml~5B0%k|tr5w4UKGvbXly;}6Uo0zGBZeQO83CjW? z`<6FXwD#d|qHh;7aHN&0BjMqMYVFWtjj&dlXO&{{?+$QIy@3ZXx0Yu{C7hBmn zbk!MjvddK{(>=>^FAaGru{U6)(eXxTNOD3fd4Lp<7%EO~)0!n;@D-2p14nLQTtPsfq!Scw+5rs^A`c7H7#QCoYm$F21X?5l z3qhClFUyadT~qxfxoZv_)5K28X8NT!69?Th#h-9F4w=-Wd2g;}QwO>V45c**)Z537 z7P&6)JhwLq@y-qkiGlqxsNl$lJ?Z~JFvMp_SC~nnqH?! z#L|uSUBMwXL~}#R$)C!`tRt5nB6Mne2iJ>feUI;ehO8C825J^cJX|y9i#)%VG>Gm> z{LYDWx|fICc*82ekaqMNvw!FFL{{Xp?Cn~~iWbW%Z})lfoN3Qi1)zqqRQ0YhXVCK2 zF|LdvY8qL?UdeSdZD!$`5;e^ZaJAegYPBXJ00>{5g`$Y}x#EF+)o{@3UfYj#JCKqJ zTmwdYEm|V1#=i!)@g;e8x;0GIP@^HM#*+>mG0XdCxE+E?v^Efd!OJ~+YJ_TLo?H??(Ntj$&2-&Rd-fZ(u!181p8 zC}52pWKZ40d7XQ1BC0v_olSC1+*q)qHcv4-tV8eoo-1*g-8M{%Y&xfrkwNB4Bs+44 z>1@?$?&f_eBhI(2olTkeS6r#MLXcP?^BJ!A2Br6=n4yBq-|PI$i#S3(_@;pktPpSY3zQ1as(uO^ z_tA*lw>*#Xx*j=U3+plrD5VE4s!rwwb)34jWqhHb!R#K!+?M5Ur10;NI1ge-PnMnW ztKEGqvgX;H31p#?`8NrO?H<8g_p1iE*{q*9u}s~Zr6E$MCpscle&5D5Q`b0FhS=lZ z3}w=>i?PC5WaU89k53d{Q6y9R|7#^@PP?IS3c1Zti zy>8=9Tq{z|EyUrPtd#z__-u5q(sTrLhzw`qTuDR=?YF9XNv*vx*9(2GwvWjGhHFDc zS^@sny-8Mr#5T~GdH)24m^!=*0&X*m7s37qxb3*$iDMo;gN=8#``ziMc9hP=Hu$G%G1@AF}HTh$0{Q*U#^O8f2+Ev5SBu@ z89U94*)?}bVfDvdBQlG;8|tcA8KBinD{K6Gc$Z%A^UFQb$GTtB<`bsMjzbkkaDxEL&+U`tL8i!ONPD-ZhirO!OPYhf+PxL&{l>)nw(lq>xmLiS1seOudzw*qU~A zd|-l8JuD4qK@d5>W!2P`sZY8lheWA}wpfp6O!|Lzd#tb6&r`*Y@Vq6?P&CgSq4jfG z)v5l5s(O9xlgSVDKEGB5EFQF{@9=2-E6ZZ_X`!J>b@3;(S{&6S+-i2-JTtf5p-yWiH?PUZXf-{IrTN zh*El?|FX03_O?`J79|L2KzS|(VD4(}3Wx{*&N_TxQK!X9_r^135i=5Sq97otuehWo}N4fxpBf~$$YY!=p;U0nG<^BZR_KS49W{JmrANiW*Zx5 zdC*jPT>+)d4Ptoecp*mS7r}&bxORj4^XQvdgVN@z(|+6YH3sjR*~VPeA_g*TX5g^8 z#OSq{GpFT(0$azCm0R5oy^X)&y-m>%GZJLwxp~7KztLMEbyug*qtHUA(Uso{v2z+_ z!}S!O5r?E*YpURIoniJ(%~UJpV|@TBL|tc}T~-G%L~K9z8Z?8{w0S=BJF;a`N>cok zVb+w{DfQ;v{I`zX82&mlKL+qy`Zt-*7IBLGl}}|+KV8dk5*Z$ShnfqBH*d9((NWuT zH4`XYX6ovE92&FpI3;j_Z(Hk=RgEbCN@F5pV9 ztdv0$muu-Ta>My-uH5=thpa67%UI%?eud$n%gd-LZr`zckQ^r*G7*DQgr~Y_8L+^= z(D2ppL{Zlhw{&t^*rOZkr=dB7rz0O$S__lvo(x!{V7HTO(9`ns{&*8h+)CT)pRl}I zD#2emSDn6*tMtPll4tePl9#FMJ`T2-F72=?JCQ-fE$1v?{+3+^mPx(Ft{`R7LX^5f zFjUc{Im~pae}s5FX#MQe^{wc!DWhc2C6Tm5z>C0Sc2-)=xR-AvN|e&L{>a_s^hLR} z1-M#$P75|(21HzzHQ7rg->!&^X$L+Qoz^?D9f(Y4>=SAYQADMFF{u=791W`cy)S5` z)m662IeJya>p$>zth^F?51A_)Da?9nY9HB{LVh&PAF%nr;r(-(mGu1Q#5Xxc(4p;) zIGr5H&w6?X1`l8v^vIi_TBWdl;^gogewJs~*2ovh8>nT;IL*^6eL|)y{?I7s|L6I>gWi4S z@u|`cQmstn@i+?J`bylc9R>tksj;nIG`et## zUh%3(&>o5U*Jk923lfW%GSx=wSJ|MuqD2p4V8(Zs#_;5DKe~3-&`>M&%kvMKY~hLr zXOQ?f$hU~Irbi;rV8qhpaXEW8@D1m#{{fh4B;wdG87t~w67R9az(z~O~ zPC}IE4UR3ql~&;nQ8DVxiEW)n>(KgJGQY{@g>Hodb$;bi$&bbt>&5BSps#7NW2;(x zy!lJpFkS1J8_uIQ*olFIr{5%+d!iabnFgOsj0iz4D7xQ+l)RE?_rzm2yEn3p)2`sz z&Vdi%;g8a=A6B6i3@Ie>zHl}tiFv~hqUuM(=GFh^y)+%ZXZ{t*5r#H)z)o}vzg!D{ zaWKil@FS)caFYVBGcu82i>)^(8j=Z-2_S6`-T*#FS>v_UOBwSWkOqqt+5v#_tfD{m z*Z?X;)bL#ZpEgefbz zrJ*_WMxBAE%tZ{!G1Milb|l|5px~Cb6*+$DBzq+aID4C;N(W_gY&Wt7g8HYj2H5ne?{aF|Sgt1Hri~4{WM|dKr zMO)x2ELrDSuoIXaS*Vul-pjg;!TPCx98#m1u-&17X&p~ZKMDmlE}+580!>a7uX)z) zNeJYC4;~}%4m>ycZO?dDZ?AhqWrN>+2DmlDM)1-M`Lwl?B0Rk@!CLg-=36QjF zpG|QRLH`4A)-6_@8oIcJD+kk521J|3{S)3rR^VY)o<=rJ@JptK(}o+mAji#CCs(yJPb!C^{BtlIos6x2UwOq#I=GzJa7dH9Bz)lB?jYB@xeV0 zC(IG}l*k71boc$J07Uo)CFXb0F<+C1Z<`RzpA!GTeaArjOI?=rzV2IU9yJ+Z8!u?y z-udk%UKQwO`dH}$?V{@2y9FVrBPSICX0RPP9&3GV)KTGT#9YeWY9ESDq-dGn+2QI{ zifv*FD3>Ap&Q{@1q>GFI9q3xN}&^!HuD5HlRt{@uUp2i{UQWQ zF|*kw^^97e;i;?S<)%$`S@?|vdZj>(Pohyg6|{z%WYvIIBP^U$J3s1aK{gE1HZA<4)jqkmFP5-@W-Il7fToF1PvMuRE9*QsPtLJXzVHX$#h}{=C!3 zpcceOYskRGq*7{K&Rl%rGURAK5$WH<3@GO;9H13**megh6 z0d97bS!vY7Gv^*#23)L=+~TZml&)v!z9r;;F9O5;b`!=@`9f`CHbfkihCpEi$ykw3!+r)JHAEd0BxgBJu|-0iR!ep%*B4C!vCi-ATx}6>3KYR?Zy9j*;b7JB#coo=nAkl^Z@WHgOem+<3lS z!y_)72fR#;2_wJ-kEf9{;{|L9a_#0VPLF|K7i=FyR{Ip;0uAoUHfgb6epkH2YoaG* zyxIsXA>IJu`FpVK+!k^Awv_Bm(BVU*gBJ&M!ox*rgw)6VAw2M~={U9h{ekUu%8#mt zBO)Q%wYhlG)Y6|CSX+P>)*8f>F$wDt-7iQ)HBiBQGbCp1?Ic~?1d!R^RNuwq2ZS$XOm(jPM8>dbb_o^>Lpz@m(BSA&c2251s~MLc7AbBO!qno0r8!m@P6ff z$3I%WHNd-5q=o_NI`Ql~E864DtCl)rdDycaC($5Piz2j3uZo5jsb;l#%B1!2N@EyJ z!+|s0K%JrY@p6sfpt(v$G(cg$11hOMrvB#x53R&W2IF>3>FD{;dVha4S`#Ttw{*0| zU#+6z z{(WD3KP#?Nr!^<+*GSoIv#ciddawUH-c@zIXYb#28PeS9WO;v?W(|66wLBR4+ngvy zGtbk~Mgcao-xalYSg90*Ogs*5`^erwOiGR-G@3if4d_9`b+>Bzbaxh?YYNvp+7+$8 z5RqGh)*fA9LPj+iR;h4$r5|7|D_I4ta(S?j2#>~3%`gZJa zn5R`vYJ0h(VR(W2m|T0)ynlqQXfq$!D?jijT2P{L&cRIGDB_$s&_NanYmm z`b9m`AVKy<>3hBbOj9bI<10Zn>mH$&xPn5ASBySFZ6y`~Ouq?mpzXGDiWJ!@=k{wf z^=n2YZ@tOQK@~A4fL`uk7TQ{(N4BZo$SP-NLX7-6&L(B%@&03#VQoLCfUMr6YbMIJ z>S6|dV_&P0cWGPLvOrJgKF=FyXX?Kzmty!-Z^9bl%sj2@meeO6>!bv=l6_j|x3bp` zRbr;ipL>x=egnN+ThqEa(6sn&U6HGXV|J^Fa*h6j&I?DdP;2PaqcOGGn52#{FKn-@ z*qjaI@$F_@?K-gFJ>N(z)prP93ZhOpw2=60Yr3RzF&u-{%fJD0=Tu9+i1XdT%FciD zabr^#r=h(A?fd1a@Eh06nnc>#iah~_@hljRx?eP=jhPDqxKErHvfY_6B8s>o_^>Qk zgPf30r)6s)`FxYy%$iEJdxNX%pw}?e9+N;@%Gx(jwhH`!B(IHX!N9!kq|8u(@1)s0 zu_majqF63XhVw$w?EDMDL;nZH`Gk=Xyz><5z-EX6IufD!AP`>i^hx6g$%mE!J}ubn zaXg{7EfPP8ifj;gQmwwZnBkpUgD1Mt)Ocn)&d7{6hv~Gyve4sA(h|%MwCr$~uW3<_ zV}hepp3jnP0W!S@A&3}TYW7yS0FPvBgP+0e^iU@@TbcwX4n8Ccy6kil8iZ!KB&C0!~Yg?~oT)U%bcaAR|>e4UGaU?AVE7{WAG54eE5( zif%vtgOKaV;#?x&u)TVihow|P-jZe`lg~`*Py7=f{>`ipCm)_LWS6}n>9l5`{-H7VFr;qtU?4!);&Oy{5zeyf4(*Te*E@F za9%J`=Rqg555c={`^nC9ge~ir6H)G#x2Q!Bnc5(V!hhjN)Q) z=R5}0%TILLQ%$Rs`fg>*%N+L1C^!zvvPTj0&rF>p3F4aBt$|*Vl@=gA3I6lJSAOH7 zg6y(Oe7Y~=Ph`j6RxnYlXTne;Smjia^7_r&6;z*SFl*qjZEFRT>f)5`nVMog zDYDlv3B>b6LqXHVHRNtefAkE~4Ss&dbI#d8B3M-mv*`{4lW}Hvg57og`lp~w=^uSRvkB=Z9Onq5*?uk$(nL*9C zWY`^_6g&@LlK6DL>gxer2i-HD#j=^O)|a$crM)gkkB*V8ZiN0yNo-8oSL{9a88Zhh zi)5ZefNVcVygug9fLw|b-y{n6E_bo1rKTEjCUU z?sec>wL#sulzI$y0}}GS&)txU}C^-CVG0W2H5xa#@>&(%^7sTJDrJC(UjcQIFSL(p z(63T|kRXFN*|_ngPezZQ`lnOJI2ozCIB&nT>O_l|K0kB7RMLEhY+csRcYe6#t!D%5 zLktwqri38pD9;Qdt%c{5qe9GUQnAqnon>dM7=yt$vf>?!W!~z}CPi}O$bXq3vv%?j zBFeJQTn;szZka9@x9mpc_*%>6Egrv*?m-=Sys9$t3RKR_>v+mEHflNc1-rgN7~{tq>J(xe zm8h@~^c0FCXojA-4ApG5F@@*54io3Dxj#@_SI(R>YoWZl&-%2-b0b zEpzho8D+P{A;?($H+$1~@B5(3vicr>y z62FWqBB~8QAhl6aqOdeilX|`+8lHWINxn5&%UoWQ3);f#nbMgi;BGZ;qRcQM)s#v$ zAKl1D+E4k1AA*~P$)9ShMpj~|JW*SqfkUGgG|(ImY?1u8r?mL!+6Z(`J}-zS!?ICN zf=^t_@tyI95}lk0Y}NeCyfU{yu)1fU#?zW=x%$S7VdPucef4Sc&`3t(2`}{{*wPh& zEDt#%19B+iN_1!??DXJ-yfnRezBi=v={^ zIWyYSL47=fTYK3Q<8)JSIxqHpTVP#tfp02!F~?_|ki?I1GR{VVQWtjOya^u}=t(cO z8iEc@^YvB##5m*%kr(o)t6rW*QwSkGa~oA$kgG~|MLTt$DTKSkUo@S$Xa1^cY))sullwX2|;jAI5xGXI@p4i#{Y0JAHT1cZ zx=ZHcZml*`eZ>+zo$H|nJabk5fmMpZPnFoB%`Z&DTFmQTQJs>GShjWgK=F?@bngn3 zM_*@$XyV9O_Ww=i#dLrvV8*^*x&K-Gj2&iKV$Uh6u1u4ekL*nHd3I|=3%t17Q_#=T zU%%8!*56Nv{y}OQ+Ef59-blk9I@lPLx92t1Vge<3H#q~1r8ZH{%4IjeS9q!2O38x7 z3Yypu}MI4-JcHXy1}{TOnqk>SFRGeNW%+> zR}iG0En(2SsvyfSpEboAx%KSgS#m2Hu7On=6T6cY|?bP=;s6KonMVzUf_#4OS7Zsli- z9%F1s!)2aHM5Mqra}4Hl{E%!p>&1~lP9B|BCp_a<9#C;u6?nZ`^NmLTO^r%`tnXd z8Of(CI3$njTS5Gx4G@;*5@C)a&%)boS9}a8$6Rr|;Vr^ACs7x(%I$;%+HZ`=gD_SJ zR$rgDHh(p(cdlSm#02R||0LWzje#pgY7qJ*G!c_-X=(>nFt9HyWw_FJc^+t3+e!@W z1diS;!i3P)n;|%C6|GP>$L&PJ=XcccO573qlC`6v!F1fC9cOm?3~IHhj|kb-v0UI# zkRN-m9w~S3s|9y^4GEEK{RB47^7{4kvIyR0u zsF$ zb6U3b35RP~bNX6ntd)I7cBh>6_R-3#wcFmUJpdLW};VHgt1=~rp*mW1C;b$XRr5mkkvG_ z5iJ6^m<-kUxVyKc!C`(-DbSqUbL~Ab5Q=tlH7?t2NSmIAzB0!XXu(dFUnc6JFNtdA z`{k?FbqvtbI>xPzG-cQdOhUrR>QRgUNSvo%BlwQPr)s#8D}Qb3!gI>4Up@P`U(%gJG`L%4aXqFOG2_DGz`12O5M}r zpLrbY&$MhAuw-I_>YJGDlUBFdDpB^2PzULvZeMcOWDcteysj}k<|pfLX6LEtfDwW{K?f73))MVt23^L|{-6umg-*8BDW_FIoI-5i`- zAHp9UIkYFX48CuB{JIb&pR}A%lt1jhFHXB2A3lrM3_fX~ufu6pwn&Mmn zZa9IR*-M$sRUW~&qn^F*iAKeKvYLVoO%#Mg%wiK2p=#uO)C!%IXO+#<ZYK3T(!{$QrDkWGcT@m<_HnUDTX#zD>cZ{I ziuLoE_mI7kcbt0t8CG|*+d-1&uc08v1R^TA{H$?WE_|-}2}a z;YhO}eG+l8+F>oK3Rj-ID*-yIJeKJEM#QI?q%1`q%R4>cE*S5LV!4y$IFz#`NR~?L zw#w1B*W$J3_aSvfNu6}YLD+b_ZOh&8iUp6hq}jEyuGYS&cTzjjN%fRqZ^ot@-=~|( zLcFtH@wA+RDiCVCt2^cE_0gripS3lb2K6(CL75xE?>PI})tYQCo|XWAw-Ajo^)f1y zrw?r@yq=*8)(2in@L-6ThpV63DGL4ga@ZOa_T^+jjHO@wcoaU)G*v&%WTO(B3+3Rb zS3lj|e=XWcM02pE{aPl;%`B)=6E-II*c6ohN#@vb}+OoqecDL?M9AkeV|5?Dc z75b7}36mamGP2ad1TQ;umPS7~=emZYyh04`kMtB%W9(YBPx-{%xN#YFuRn-eu@4U$ zQFK+omkljGD8d*qEuF-RU#cuMypuuqbaQO}YwZ^y+$YPz<@scijnoy<^3t=iHYvM( zx~yK=-{=%3j1Ggi53|%YpuZ4TEYwL!^G4wrF-ByzSw|KzdYB(|u)CQL-w#|^)D9v^I(sacOub2{`q z-;T>qGewJjoaY@2iwGNTQ20>5-i9odEa za?I1)S?JLQi6DRooAcZdj`Kg_3azk zG33lI`Nn=BPj89JZIrsb!gI|Y4{iX2)Z_NVO5F-~o05a;es`OX3@OlcoS4Wt70 z#GBon;;n6Neglzp3OW2X#=%!~R6TodAS1b0-)^!zyaa8)h3kNo?IU=U%7Scc*~5cHVIl)Yqd5susL@zsC5gfC~Fg@ zFzY2{ETsVkcL+6~3Nw~-bqy;zSqy3`q$ZGUsR;+lm7c@u28oyGf*k8tpH*VdUPE~&DE6`Fm;~a^*y6X0QG}95RA$k~8tN)4(F$*jG-5jQb)Z@e z&94g-MRjaFsToeiNNOqaQxz#5GA1a#ks5JZEJZldzvNyk9B;>^)aNB5xyLPS;*M-c za?R+`=O)O)sLJw8U(}~(X2C{z1nI8)#>IiF z08k%jEV@&wq^5%8610k7n@7zIX1b!8L;;s;oF3R<4?@Ck7$1^T@tqw`6PZ>vww3 zbWIhhEM8N1yq)zJC+R~huS)u34X%>8_TuYa&1dLe&A-^FIDX^$uZeFT{>igaSLc&9 zPy4>Z8gBNAVu3U*d-KvV3yGJzo20L;_NyU$=>7b)I}kZwt*qL7TfG(H{Z;*+0RhRf zwpV0pvXY+$(UpxC<23upGd~mmGR8Ar^_4X)_aS-ZU!KO!i>vVW3AW&ROXpT zo+&f7o5UUW)aqgMxxo>#zC_0tI9nA8_|t0o<$OUZH%mwq=%p}`%%unRc~90A%RMQ6Ssjh1vt8K8C3K``GPP0qnW~u@HXm!u zung4f{1rE8DZmK5EAGL5@bg`!{+WPobJ>*N|GQ?bJ85dkJ-W$QhprgVg$g92w(apb z%MUq7?Qs{%z7o|ZmHCWR`ngXB70U!r?aMG8WT;Y{5H)p!s^y+&dP&Cq_o}?+AGO{z z5E@_=+jmBlXHUy_5YePHd#hk##-NisP z7=p+`n^g82nmvC$|Iv3|hjFGLVml5Toz z@6^228#xNE8AkZSqQo-f2Ur&|27< zYW^UM+rmKmc8@OXMnFlcXO4uN=_iO=Zcy8zALt9=s-#|!zi4k=t#^ar z9*v?xMpBu;f>=^dZD14IOqQcX0c&f~;@q`QSz8xFEN--`oke<=XFglo|9 zgDe~l-Ljccpm+&(`sCEs=dhsrpL8B!;?0|$ITdqbtKWss{TXXkVP&t(GG51Jn9J=e z(7P(3ow>W_)++{H{KN}mKNkD2vhde zop7k#^3@a&z&MnDAv7pA9r}2TeU(e~p-MA^Z)lt5MdpL-I5j~&f}f~f<*9M9u|zJB z`peMz=O`Is@xpWNT^blEb3HI0cd2){_2z>G1~*{8=Qap;4^zQ?jL44=o&Rw63=A}H zUB$(@4uj_lkciI6CLQC`z2Xe_ooPq*ylW^2NE#mgLz1Oh?Xd77%?@iY$%xLLi&3>5OQhOd@-ZjIPh*QUf1zT@^?%Msgq>JNaGtM~_!$?1whFskSpeh8 zjR$sKQ89Ar9eDHO9?Q9vx1+ckuc6FA<|b^B)B+ud^Vh<%Aox#T!!WsgL-t!Za90>s zF)_BIOPRp@r#AYlch+zYcL0EJPcUa>L=-=481sm;Z~y$raJ$LUC~N!!B%Ilit^_Po zZ=R64{qz{)c()D=#?+7SyxR3#zFU2;|zw< z%Hft2)IM#{-%GV}c*K87l=>|cl0i1fq}#Y^g^TZw@CkrF{L$Le_8@(ZT5tLi&LI2t z3Z*mehf`RRda7$cQz#^8O~{pKAW28#eVfsL1J zC}O@@;}st=^Yb9d+i6F3+a)`G{gFX&dn|hBdz>qp*&3r*t>D;0G<=*)tQAcUXa1yp>Z(Y3d)^#Tg9@l z{!&hKtPDUGGb^akpVAYH;@?STaEY+=Q2K}Z8qYsln>2BZPiHe{zkMgu_o7|R`y$K_ z5}6Ndm@Ph!bC4#V+1JoiN%D0z2a-#MQf_7K0-<;g_ACrTAgv8r6D5dqezkiG!4wZ_aIo)cr6A22dw&{S(Gj+tKI zERj~O-myISEWmha5kk9SxYuQXOIMCufMW*jfY@dE{M_58`1#uq3c>sH+SG9zBI^Q*brHK&c1bMkj6>g>@PbRzEGPq z&nO`src9cc7B%TB*EdimpvPw~AIast3X;%%m?z0-W_a=B!_&tMSW|f`y2ues-COr5 z_m(aOYM~ayi|~uT+;+BZ=ESMRuDp9dfMy-I(5d3!ZZLX`-Kk~ZCF38fCms0Q$k`6t z*RJMywL<2tg`#h(MBmmJ7u(}RcIZ;-4bE)$%)%)O&%HWs5K=AW*9wn&Mr%@(ROVUM z>eassnXt8Kv>P|@O1t`TT4gzHjFh#o4A24%i1~#?>8SH7-TT1tCttDS0|LN z`BlQ+mILOPIm{vIFNT-1(quzs2eN3N@2`|;X#-5WYp9$S485+@HS34MjywH`W}>&w zkehkZ@`!wGWwtu2ACm7oIV$N>Y8OjAxdR~0N;97nz@nnl`2`bbHrKKQnAD$|r$c)O z+7$J0d>15F;gJ(H+ogl{D#3_jyKvF30IUvPXT1%pNPe8gS!+H-{*mUuyfjtcFiR&X zCLy6}qV;Y!d5JPXNw%pe+JwP8>kMJutcP&e+5Aym(Ytn^2l+|vESalv?o{=X9M7`s z_|Zxr6;c-^dl+bG`co}@K`&@HHK#_8C3M;{j>omcZ4@utfmzHW6Appa2=&u!gEP#K zP%y*Xw&N^7U!=n8&IHu0jkF3%WTRxjDl2pF){F^DyQHCucT&w3bA%yLHJf}S3a1Ch zv|P71See+J@&BSp181q=#DR>3n)Mdo3kiB3EBgh{P91sf^hpp!oAT6?RUd{-?EbEpy=`o~8N34dp3 zPhTih+(MZeWFxaLERyeoxiWa}8p5^K(ae2~iIQ77vr%r`BnZl&BsL84F{cCUNj zwDy_;>uI(XZTF9eNbj2?tMV=+|5I1Iu(HY>CueHAiohVisHzp`C0SZlmet&|ajKBv zRv(T~nH1O8Pr~*#g5AaNZ5gN6d zs=OR&W$_+hdw7;ha@bSRVhH@|y>Z7V-#iv>v(35Ip`y1%jZQ^6{^2X<*={v!RkvE{ zS9>-{Y4D(%vfVSpt0O3fSAT`ZvV&}xt*QSb0_Ju!O&4^=Dh~*pgW~lTZrIX^$xSC3 zHqp^q8V>V(mhbzFgO~#C9`kc^M3xox(&@O98`@qT3iquSDf}cglR}xcw~A@GTmQ|DwEggiRVI7;mu@D zY#*mAvC=Bct9tCh!hWLA;XuUu3ZXuRzq(e)*OLJp%zq*C@KcRQ(lr>kl*&M$;t$tl9vcnN(&t;r+!&MRRB3Das>?j!<{DN1rMTto zGC<(T!2#S=)y;#0EN!t&=`h+c;tKD$qGg^;65wg`mdFrgZ!z%ccmQ|tB1_v7leQft z)xy!2m3hf0H7 zL7B4ohzGmco+r~FKhxS8z`T0PF{kKMW3LmptJ0F$bw6)a(OsFN4lZ5uClpZJBF-@? zXG^cc&3nr{#;>{XdzPJjuBPp$tBF@1R4i#)o0WufLiU9UKV`fW$kge z;53uacnlUD1xax^%ww_*ZO<@c&V?ygnlz8a(qZWeCRBV|HlW8nqo zAEM(1N`Sb?IkJt;bx-7Ny&gU00jY^*~DRP;eg(AX<|cb}@xuLhxKzvlkUtNCDGIgaerNw+bDr+EsS zd9&8~yiINCe+t<7B=&2xI<*4)U+^4qsmP|R>J0+P)9T@X_Wc}ud0m%sP6A82igBxw zq+R}=koKi)dANZaLSVF~>P9mg0IOBH`tsbmc4_kD6fBe84;^%{QQat{gCp5jAj7|! zGv-T&v7pN*B zL2T)ynS!s8d+h}|8t>|Uh9!08d`(aXf`jB*F= z(il!UQ4j2^Vsc^`aCt__&4D= zS@zQHf^3@qd(B5p#}ems*(fyKJ*yYKB1bgAggy{mL#5o_UeT>-vb3JNh4_ ze^+gG)2XHZZE6P}!bEDuUvRy+Ejn#Q*_JWFFo8L<)U8rTiK@g~!V|1M#2Y<7zs>xD zD@7>txkKSI2`x1hAe56pBiRO8`!CFZqvoB?dNV|YM+W*A(zo)`dCd(<2z=C;d8Fw(%J;v zb`N-lemX6rG;^L+H1IsfLkAU5rx(D)*FvTzk^y%9PlAC3gZNNsJ;C4qiS25|!}I)C zYH{}Zq3I-&?``WEjDGc-Ya+{LEnd1sHH5Ebwc7_hhhJ z*?<-b2-E=CGPB7So}QSTP1t!y!aU2y#Q0P*Tc^_3kSAFlLb)iEsy%;whT zd2wHhMEzNh#)EP_X&9-m@tLA|Pr=a|$1p)L<+5{)kt)f!p)bjE`T4>%~P~$Vu5A z;S8+*=xyg}fzT2%xI;1HQzDhjNztlC6*!}iA+mEXV?o=k*eo32jiNXu`)`FUwb!tg z+_F9bF-lL)!HNxGhzcN|7UEww5mxF+X#enFS9hgfu!}3#%j(n4Py{XoV9{p0-3qY8 zsTQW?(N*1N>{)ECydwrxLwA~LgSIa#jr1tKojJY9t6L^qUDd~I$?oxffaDCoNRBBF zKN7~A{uH7412lVZ|Hc6v-&hfapM-Q$@SBDELo{hS)R>Sh3oN>n4qOW)-CLF74l2C- zstPZBN3`l(eF%T38t_V@Llo>$MHGw+C7$MWK5sZ+}%h)uuG`rZ{ zkEel_%^WxrcS8Seo8Y-BS$ zeLcRbuV6_irC?7lnn!Ss(BQqZH9|`22!sZ~Gjf=A-1_CaFIbi_MmG2sF2E z=hg>b5h6@jeqC_8idFr@m6snUmUhzBQNci_G$P&knHf|-+c~TAE|{X@=)~3%?(zDupg#K3cZ!Wi$8`@r*nE?=S8v(+ z(P7}Y)XL%qpewReZw1SI&&8+C^ne)knxa`^s3@UT;v5YZ(7=^u|9&L z0>QN&>R}-6p`P@TnIH#v8F!-$<^WNnB&Q!~nGy2kb-P`5m2oC5>`1q-C(+g>U2_B^ z>4h-)i4q7_t_4t{*FZxy1fydQLCaC{n4gB@Djh!#C_}wx=Hw;C7VS; zu=z$90LVFti<*q-3)|R)B|sb;oWmHizq5AZVEcG(Ix~vz{}k!Q4x}yK_1wm+lma-d zwE44x-8S+in;8l$G`{xlIfPzT=Xn5uGAoQ^yn#oC<%;;F;pah2m=g;V!LU^pF(-9r zwQ716lgFecroLC-`|{hwKN99fED6V}rgwk>*mu%}aM87Q2Gd!|ZU-j6_4WdUky;&K zhFH^`^ZXRA)nzN19~@`MN3+8PE%-I{%V1_d*Ind^W}N!JOCAgMH7&AY1K4Qk)-J4S zj$HiNd-j$0Pb%pF^pRD-RYLFy8I|B4iL5CNZ^WdsY@B5-r>H7_U(w(gM%xtp1CUXS z4lHj>Y~*hIEyonTfgQDh{ks{RG8g~0G9Wy;)}RL6S7kN*GUmFvB)YmFd(QW-_|nTZ zI~nARba#HTb4k#{LaT1F&@TbFTOH>k+8550Q`%T*Ixs3+zd%m!B|GMV915T-meBUb zaAa8T{jOa-K!L-Kr9(O&%IcZU4FwvA+2^E`yG1dHF2)aKIP`Sd6a}`9s_$iuAx3)z zc6Oc|nTDeL4!Y@N%3$M`Yz8d+@=zd!TXE}M8wRf!t>@>PdpTvyjao*xy3;C63|RC9 zA-~hpm5M)G8VRN2!Ahm#A*3dYuVonSWhX`-uB4$rE@bqqDW8TC6McYy8^Nh2YLXj) z93X`X!@gty5-1R=kflSAxUasH-{?i5zdy`<#{5O^IqF}li11JKT2p&bGIFnYlmD)zf9N*wUU8#`m{1zL(Br0Or$j&OP3aX!Ch%yG93vygmQ zMth&tF1T4~@&D421@|z%X z`4}~?4jZKCX->ZzRx`)1{{A%{EcQEqG%*xU{ar>g-co&Z1gBzKDVX13l+|gnlCa67iWy|9EtmxT1KkRnBxUG6r#ohULxP=~Gv?jrU?*Re9OiH!~M|r%KG`ecO z`){EWlRV3f-=UWDN+s*~jzTf@y#n)`yNk1>jDkt~Q2+4gUlu&>PY&z?1ZY$|vRr&l zb=5lH)T6y;h+cnny{jtI$zJOK0jtDPA=x*5S#I!JIhGx+#J861ygu30?v9xjqM8UDbl|zB2fiaQzWe(*JbI=UHqBq#N(KUEyt5SEJ2C=g!`z zN4x{V9{G~TgT!7IFGP%5ZS&B*$n2mrdthiSkzFdpD~kYA$OvbkP~>Jpl`1UK|0%oZ z_6>%BQxd}zT^GooeIY7AjUv|>(PMyz)BsX1*QoFuTKV3|6G|4R>RCei$tZ{Ub^Jq; zIT@viIsg4KB<`HZa@W5yV~gea&2V^;Aw1tHCW<|>HZrzd!94TKl>>tnXV|Uhp%g$N zCycD{{DG14C#4)F{+%& z^j?!B7tP2q_xIQ&b5wu5`MV$v)%95FMc4hsgjfakbK>z=`5Ae~35%N49LZ4GA5*uM zZKF`P?SB(T39ao`JPgRhRwYVkslA|0PtEw(>qa!>5&gW!Yq_fF=F)C9F@u_3W!=L^e53Qtg$$0!K) zl~R=)AC1kbGN;sy2^$1*3&+vX67?MLs1lQ(-)WDfD#5rOG$;1BYn#MY7{i9DY5Ff6%{^YE~oX}qjRyoR9Ew3-9II8sJX_B?oZPi-_jH_J#9ba4?nC4Sw zdpvn+0*m8|`m-a&p6iIIPKU-Hr1{Q`B$aH;?qajz_e0RtxR9Zd zk6-S#^X#RUH7@bE2dPo2#J$p1Y3R(oQIr>9*1UHPqx`V1Bt@yyfQ&+UqO;16 zRdw?21F@cCgQ`Fq`^4S0#9HQyH(w6m-&AE|##Uuyh6=ZAg;SC!1UZLq_9}C2g_7vI zh_?~l9B-^vPWi-9+u=SPJWcUf}x^m4?xy~7jR+R4PGzaMD~_Q zCC>lY51Q?;d7Q&|@@|s+MFhyEh6?g-S6>k?U0h%NJz21)R}J0Kj?7C*;P|Rb4$0qv zclq;v%x+MrjnSl|-bFoXw@Rby2XDr%B(6YL-D?IpwnN0%P!N@hzLQ%WzppCJ!Nxhg zrtyTnwuV%<)-H5=g{moKFd3<+3fWbocBa;E23u7RoAWwGpOdtX(@JzW zYskRkyyx2Sym^?#;$jOe!gU%tU5`m~xIzvdQ!K~CR?jZz6B4^W3@n_(2|l3}J!9-E zzu9-|3D=(VnJ-=;^Q2abHERG=sC$5vKG@M|ISi_ zS_I?Tm9>qrE6QtTkL{#+DjzKO^Z0F5*awiRcfPNDBBKIs$*kzO_hpLhFAs?3HE`FO;$j8A8bqrYjPFsyDJz@JFUwmGuDp;Zl~ z$Vrr`DSm;iT^nr*xFyhNyqhXVw~#0Js6RyU4N#?#I>TF8sY<#ZcR60bDFVrEKi+7Bv;toA)zNL3ccxa8N1k9q(GEpTo zwKDxtdOXieM1uIEMyhXtSO`a<%+ibdV!Wx^6jv3Dcxc%%!}h{$ z01MNM#dgN8V<*3@ANxH9^AExJF3We$h=>JYc7n(&<{x-KwM7SBInb_5Nqksw;%DZj zr18g?E>3$IoA1#MOiB0Tx&QRBdMpsV+nrs9DYoC z>>yVhTri%oCmfq62|P^ zK8B~1r7qa-Nv=k5I51d=80iGkY(pOIQ9N&4^zO3Bs237dlbcks$NylVBd~N4xg9!^-4Z>n?|m=jn#-u8%&i{=_ck! z_IImBJs{|$wW}FfzMq9chn`*%1(yozX$AE~h2n&tb9~ool!#p{^WdZ?29%Jk@RqBa zRYD}icHRoNc_&8=m_B#Ln8_W}7B;*6r)f;d;l(ui>1Ue7j}j%}&F{tQ-WAWCf$YEr z7ld>lA?A*n{U6f3jOFv|fYi+^b9uu=!|v?;%4aWz5|L!R0?#WeJ;?MJ?HiB9F_cl1 zLQ1}V)PEmh5V73u>15mJ)CD?mNoALUPmSfCkU@<-@|k{0GGmc(cfhis$D;x>tE{wzrU4L zKqC<5r|1jz5#!mTlj*UFBObr};V26YH zW!KyoPt8$w%~vdww4!=6m%nD~;*I5onl{}+UsP8FG;vG55xSKyL;aXwr2a+VA|sS6 z<<&G@QW@lqDEi41#td`*r$*zi$sNeR^s5(AYZ#Pa`^Pp1dz`Q^oIh?hz;rEK$lNPyFuTk`|(kQBqQdoxx{KI<1Cw`LYL-H61oV9A=UO4A0g`(U-ThLyX~`t=59%!NQ*x^SP=u0-hZ>ka`o#bZ6RA zkw}gw08$KIvbzk-oA*@>4VXw^!Tdzf)0Myb^I7_q1jENI49=vxR~SrZYJRGgK$`3d z--Y+{CA2CGfZF0GRj%+uj?vCk`XHV}=5xJG6*_4ODmU(6$DxlCjupxX z%;iqHWU{d?*2z1`0EU>hHGH!D%}EnOWcgTkvL_og zyBXvmkWyL28tT8cpqC*>V`1hY*?B^WpGjuw3P`1w|3bMJIT|F{e|BuHt17sFC_wkH0@mJ=c*sk!H z{Jk?=Vc%VV4nPy?JPbnlbQMG#-o*mJs02WuiA7>OC4@8%GG8Bq2LLXnu}?WUhnR9tGqVqw3OEajBu>d)ay)4s4X5R9SnxwU$ES zY}DK5)fEmw_ZJH9snoPw2Fm4ERY(ioOKolEI!mK^C;8g1CfZ(!M7+qFU%_1)aTyam z@dN8gE1$I;yKCa6wjF%53=^EnGVB|jS{ITZ|1mmmB#3{IbaT4nU8W1B#s%j2_3YsX z0$>V8fjrEwLja7GZ6D)#$`rXj?|e}%jB9vmSIO}`Ht`p*^a<<;r$u+&~e_Sc8I#_eo#;IYZTwOKi`X?I*G zDA88kEmc=Ghr)fgeg6|Sk3V~xptr8{hCuFBV*o5Uf-eUk_dy~ClbZqJnf$M@rJO~9 zqPc@eo^VUTj^xuR^-H@eXR?3S=$MtDOh1?SUyDhO9G$iWO@^9cfh0E%i-h zDdx;tIGs7`(=-WGuDdpGt9?(Dy0M&va%z0E=DD}{=y*tlfx0sfuHa743cK3{qgupV zr}Ze$6<_vJ5oQ=2=CAatF!zi^yuv<2pY#Ab%cVMEUXYnLr)<9Iy3b?>JfTdpqYm11 zY|0Gm_?JW0+rzVsSD-Z#AN@54YFE1diw-Ug?Eq#OU)-(?yEj)1sF1FqtEQYnsny`0 zy$c9cK0wCoetpP%u~^mX>o0K6>HcDn!IVfHt!2iDTC-taXE00$A_wXYtuzX3aZA-l zCwVY*Qdgm>dC!-p_?^6XM}dF-G;E?Baz)dhnQ2-Lsb4%tmKyJ53|9ahc_rbai`Vda8METVY)d+BjS){+i|^Ej3f1A%Kb>Iy@f zI8K!Up5I8r{;KeNjn%AV1eq`*OgPPsetQ@At*Y~e^dW1qclJ;=z;%uum67rbO;f!! z#;0uSHG1LVmAS~@@29!w?n2fAPb{WHkSuQl4@{&(v)fZa+iE9>=DqwWJu81%ue*`vi6jnVg4 zdX$}4RV^`I-_)<$4NFfZHANDa6C%wS+Buhk4A?TqJ6QU&W^3g$pVnMV9Hp##>AXA3 z3)yK`n3I)=p6jgZmEfyWn%i)QqNWpHvKGZz^oy(C)cr2V+HD-6dtevY?9YR8oLD>I zJ={vnns)A#Tmn5`j^g#~oJeEV6I~d!wX^n0(wq?3>c$Exzp0yD^MF313 zydUH=DT^0{z}MT5j-+A(=wMKS!&FkFBa?mRAJ+Wn0OEAb)v1?4axDp zkP&$djM=*sg~i!yEYh-At$u*zQXo+WnWaI-sqphV&Y6M>!T1ax{V2fXf!Dqw9S`Fz zIiIN7h#!~aE(@WH3JDe z&e|i?xh^}-7o*?jt3Iiff52nKSv$Mb_wD?=Ye@;f3|zx1BiU!8+` zLCFjGGiEkLTza+qt-5}g9R~&I7;I|W!hUKmsv=7L$I*wj=tmGj?1GJz=-XStkMQ?Y zON@BPZ0u5wJ}dRWU){`Ze16tUhi{Ypv{9ObjDh2`m(64Ba!{0MbU7}pye7f{%WNT| zctvJV++T+j0FKd1IkZ6jd0-^Y~MMtU%tdn)8g}`*iuK_mQS@ zdiTvKV8eW^a)1Ew0==**fJ|Vt2BT~|_58e^Di9G*2P^j=i`t3?jR08H z-xe}pMGXisIl(8 z?DG>OnDVBT^*<;RDK1BAsQd#=6xM2j7`>Mqc1OW~&{Zo+Mk^%|yS^v>&me^td~jHe zg+~xhai@b4_JH8F1~=No{HR8K+osq`Cw+ao4z4rVH4f8F1tqYl3jbB5049pdE716A zCsVovdLsy{rz!ehh4D-U?CazFXe)~u?+p(s1CBcPE{oKseDh~*MH?R%a#FHWWM$U- zovrdJDWChtR=AXJX8x@iTXT1|aLrE9@1VwS&*sg=&hvzj<7qYj2jB|LqaxWp>vOQ3 zk0I#Vihr@Noenx86210LpL892a!#V}yeVYbx8RJ(BC_9+^$an)tW2W1 zkFA_L+2n&Tsep^KZC(poxJw6ga9l!bl;wjA6dmgWi^F~`*!njgAWMz%DlymXfyFs4 z(k~NMnkowRHvf{0aJ@r5rj86@#3X)U!A3O+xiI6$9fcXQZ}u~*iqR>(cRLlfTG=W} zE(CL~U0aXAD>4$44za_A^UYaaqoqEYmf;28N6Otm4{#*_2`LeQ%dNWdLmJTxo0cac zHW##K(I%gZ$trKKVbBT|(F&n@QxI7Nskb99gDY(_LTu5f!LeS8RF)S(0u<%wAIn=fypbjTQ*BYLzs`HR1mTW@&^ z8&)iRBlLU0$9?;6O(Q0m(Ob6Mh!Z@Qv=5?d8s<-`u$GF_m0&aL;e5+aqs*D;Y8zw2gBmc4Ud-YhjixgwEtAU9l^{!W<~Yz_{^!(s zUvFtrJd0YDZayB17IdR)1 zV0@)jpkTsW6Q3zv(3YT+8P7qD<8gjMd;}&jFKi8#F87)}b_by93*x@1rTG7&=-T6% z?Em+e<8r7>A!lJ*Cu6iZ)F{ksvm+&yQ)R2voDz?+oNCFTO|eFc9Z5%?c*^ro&7oS@ zMkO5{L?d~G&h`D>zkmEQui4!9{rPp97#rkzm}kUXKJR3pg`NU=}}dY%x@B z$d78?95fyD?Kl5f#bIRtWc&-bOD;aaJm+bkHTST@r~+2Lz@&4}y>XZ}x(sfPIe*kR zHp`{=*200Zq1cE{w2E2VQifo@huCRO!y>;U6!3cAEwT4dZr&q#%v zLppC@sA$L}p*{Qa)!##F9FNP7o*h;D?sGUN(T;C@7(OhqD@;E6_E`|s^BTed8v79U zdUfBgk6T*uI!@l(>aUz~NNIRp|MyL|_-V-2QW~kg;Op(htL3`z4##fS?+?!<$iV}e zqW8vg(Re$)z2-A=^_@!D=XafbuDsd7skz}@N6oiK#qQ~L1Ah1V9VxmZv3%CR=Ey6;;+%e1Mi-1eVVh$^R-~3y&nmwqpXM!V94pc+B+Sj z!m2GxCjy3S9+>6YO@+rE^>ko4Kviz1&-))~Jy3gJ5?R#MhrUL~z5O+|)vhvi|DN-} zGjqg(b#wRA+q3uwJdMZ!k$I0{`--QFJ2h>km?-#4FQD-qv96MV%6jGY>EAEkxbojD zVWx)Li-vanK34mrL0-STFZY5ZUL)A9u8?@w}TH;tgb$bS#D z{D?t)@8~jKa}rV1x~6#g>t`kPLGMNG8SSN8$5p=9k7C@MV&9#3iQGD4$Lr6UemM17 zk?`Y|<9eOrubhugwIP{nb@%M19@sDWxy2mX%!z47l;O{j^>{L9@U3hBK+ z13}sD|0!vNYQ*jzu0MFnr1MI3j+S^TyOBN?-f}VR{u}!QjuZaarO7l)$0`DFSG=3B zx||fD*=^LcMaqRI0&>~22%~k5>vV3N32nK<{M9#l(daG3H-u|5)QZ*G!7`f0H^F@( zoz5?|r$6Q@8x-EpFFC*#NN72>-&U4}z~6O`=$)fBcP))Iey815t#Wvrm_E%kC@LdH zn-_G+<~nCXOW2x-qAjiA>?{Bz{%AyxZ`qHPo;lRPf-G>==lYH0p+ycr%rI!~oA&nh z-LEZkNdCtf>-Vsd|0t^$CwTy|pV^5?9;_F7e=UmsC_#1aEW%$q8QWfce#4`}KmCW? z(*7nh?CV-=Ulfo2Zplxm`uRI7Jm-$>>&_|9MeDfG^B^5n!C0FSM>hE61D`T}E%H94 zedg(qPI>rl?Wk8&hs)^g$sF?4oGEVeq@GZ-=dIq$|6~bqbrBZqofpp=u061%5Vx<8 zPTKb4AKtzD`r(0Q>h|^>YumovjB2HRv`DAdN1rF>QX{cJ>xtvo*2 z6cS_8gy>A)c{`aPEK3oa`Atx8Ng=cH7bm&W?l8lUhd^50dYW*Gvs1Hy`3NcKzf?L; zui0R`0PAWT7_DB5AVoJvEkION7~e3$DEIA(3YPX52r?PpoffMW3Fne^{5-V0{7Q<3%fb|FJLG~#aKC!*`S(gUbReM>O4ne>TMY!M9xIs zTM>HdUGv1BMDOs|6A;dK57+6yEO8 zcsGtsdWg9=@;1Gj|0| z-u{gGh_qvTfNt9l__I5;_t93qxxZ8Japym$8-LKK}@)B$IGB~!vEO!7a zGP$d!mH$f=>18Vl*yO>#^4BIQx06yfM3gOsK#WoMsGNS3o~s3X@htAR!e$tQ;ybpG zy~J)P+D)w4I!Yz?@{xChc#LQ}3$D$N*R)9sQQTN6+yq)|ECEsX*A)Q4?M+eLMsVy{ zWf{!Y_U&LPM+MCg=~v8?>hs+a2$+6rWNc}(zO4#|YC~0vj1_%ND;67@Dp(o5A?pu7 zSIh65pdUb84JbMc`qqwI<3ut<MgWuduNZJa&5xEJes*5uFaSTRjIYT^`oV^bey zU3s@;pyr^J5wqQ~<$Za_{%kN+nJ`3hNj%Rdlc4bgEMx9W{9|&r^ zi^<0I&hTa!+qtT)ab5IV##W}~K@q~jrrKFtSEz}zyQ^ABpBx#o7laBi{h9?|? zTU`s?b0qfqM$0{|xZ-_;+Q!1Os)K~TTSFK#(Wmz(H&J@lJ$wWIiFnd9%cwbyZVZbG z`4IEXCWxhuOHQ^^nl8zXpL23KEqlyPZ^>A;wPVxexwyfh*FG)zEc$T$)@-l;Kb+QC zIb6$dJia9RCE`4rzv|M6Jz2gW@h{!Gprw93a`VKCV}AGk2g*4kb5QL&nG#;Ubn43C z5SP(bU()WvnVxp}Lgu81X*#D&?rQ`VsGMS(+$YqIyTAj{l~+953vW{P>~DF-Rt^>C zAqq#%`fX1FYlrkBrXx^C*QKa&leNbq51Youq%R;*5Bgi(;mU*cUWbw>c%}~_7)OGe ziZP;iqOA_t{a06)ObRV>w8v3k!M3%drb^6lIj2uik&f>S3d@0<#DnTNMbLXEP-K1T z=0NHfu^TthEoqjrYDz6mm5MwC*Z@r6;F}Qv{4MPUNM?bl=WcZV;-I51s60vhrjhEE zWz6PbAzUg>q=dTYuu2(cL?A=`hs2t&JZ5Nqh}9_5Qv2V~x7kZlA=$`0K+hvvs@{K! zjlXYJ@Ef`~LpdNwyMy}R-IW@oD>`R8b_r+L(BTdw62fSL;9&_RL=W^K} zZsw&t#pyDhP+Jt{uTBE8t9-aXc-3xgH>%~y0^tI2d0!J)im++#VO=V328VoUfKsSP zWI48oJN3-AAd9GPwMOU?F`xmSKfY^X{4f!`N6R_7c3 zd#zLLftzaw5PAFnXp?p~F}Tt3{Yn45v%#ganEvMd`?-7WJ8-`%Ns~3&AG2F)okk99 zJvy8+S$PTit2DrPm}O_#R8?x5JriZtY|5Jt|n>+g$n@ zvFDuALoH`3WbdXRmUiWH)zhfxZtQ)S$>V6(0MQ-0~xEBm@luhuyPoohIIFeB3x-4k1t3YzPeq|cA~bDk1O7nAe; z-5F`_esj<)&bICL!Z7#IuGSgBI;VXbyMK=aJ$?J<$hq%R!@?!ot&+s7)1*Aay?Yid zpOfmU_JloUop-s_Qi5qr8@ia`&!`?Q!Jab7 zfw;Jj=so;9J}sr##x_+JO>%hW)Npg2t5*S0;m2j#G(Tmx%so^)!o>NNQ4{bNDlc{< zp-#l~CljI7otY~8L444AEQp*9Z7HrcLlp?(lINoseLAe!GLosFCTVJ<_C}I^{<;rh z_-wRaIsV`#XmRv9qT&U-h)vkG>S}mbWh;lstx{Y)!e+`$?RS!%@z}op>v<}xUVI{Bw z78`D=+}&|K&4EJ5x!6;qWc{0}?OO2yHvxkhfRIx9I>nNH854OBCTOOeb5;V+V4WSgQp?`&$ z=FfRTNFF?f7i?4&>Sgh5Hh3nI*d;PfCYy+RP&IubQ@ZB!Dau*$S;Qse2ferHU;>W^ zIUNfHW%YLid)g|V8h6C-c!cxoCwQ-G33HKO)q3MlE0qTuM+)^?on;xzJf!iNi?|z@ zj@$N($E~&Ea*@$=nqC%%)G5k9b;vr16sid;w%`*o!oUt4=y-89#w zu>MYKTbVTz>JjX?NcI`DBZvB&bYQjfJe!f?9{l{FJfGxSUP@}^kIAZcjs4EjZSix% zjrh?e$%QxuTxw$KOF6sWM}XV8k4}yFxz1zkZSQmAC2?I=_QFIM&$W)eBvyj0jDLJID>Gmh5TS5n83g(;eBArg%E1$mL86J(>Ou+ATE*%C0X)i;cO7`sgpx zV@k~5EhC_s95NF+Pny9c;Z(>A68(zOf&A-tS}`$!iIV35ls~JB4Q6onCGzJ31{tH8 z@>r%LA5=J2(dq)NmL!}N4r1-8V}<&Z$TDWY{%VM!!5|NaKt)k{Vtpb`>#5Ky;cY;I zce6{md8F_M?I>0P=7Nr*evRhRv9!Mi^wrcc9vTH|u}GOC1*=ftA;j($*LnOdea?zI z_~0Hje`$<&bB>T@R!UxV@pWB;2ghukGA!FS`MUKoixxenoNU$s84!}KAD^qalTI!k z6PkmF+FUxxU)vzr<|6gzwmYJKvDs#izkvYCQ3o;VzBI6+Uk@7f6WJ zzk`DIVT-?CBcW5Q^mu!m4 z$9jiGyqk|Y7t|Qi23;0%h13C;ARbuUqnUh`+AW8U38+^S1u=DeBW0omOh>)7Kzsqz zo7Et+1W<7>ptJWV@$IW%U;*#2jWWPci48;a>d3GO`uz%L(O^Vf%0AP&Md5)F{z3!} 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 a82;8>2BUiTV=aC~Z99Oyh-&%!xBmww_6oNE literal 0 HcmV?d00001 diff --git a/frontend/public/img/template/Foto_05_2400_small.jpg b/frontend/public/img/template/Foto_05_2400_small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b1cb2e64258285d5b4293f7be4c544314098706 GIT binary patch literal 578096 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�!a8y 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%0DeESYmP_nesdz#ly}ejuWpXZhdWjTgsGF9aC7v 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
Csz1RA= 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

-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 s&Rl{z(ROO*4I>9ksXQ<1M-#MTgu|Y_nTVSz- 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%0DGaqk`TzC2y20F6@ z&OtPQ7TvtxeM*FN=UV>&2}nYT@;@@fRhGP#>LGOKkmvUqGfi98exO%aQ}gwhk1|SC zfFG;(m7ODZOxrT`K{zZC{J_uMZk9P8Zay~wmLf13XG{+Z((TIN0men_U&$7~=_QXN zItInp7b%k+r*t+ncUzAiAE??qexf^g$?a1md!wn1#sPPbdOzRUmwW;g}O?fyzt1vy3BYu=^4fB6DwKyi=oyY`vCruTp0Uh=$*ymrc`Z4pC$ z<#+g)lwZlDKekJ0ZKASk%vT+59~N>&QfE(Rd|U�@xgH?){>Hatq@4KXFW3*%Y<% z5h)Upr0)p+Gn~cvX|_C(vFt;%W)M2Y>301cd&g1K>kJnH+@!gqrXtc3`a?i73G)qS zF)_T60HjVu2f8->&kpPfl5~5v7FvNKF=E~mOUUrRBD=2>91G@$XL5ytUrWFg2VfzX zh#Te@7KFzia|>q?5I3o~LFcYx6kio9ZRK+}I#jOx51EfZi~E!~y&K2+A2PrwB4CDVh3#>GiGms2HjD9-|TCXMm)jG z%Cvigrg~(3OQ#xD@K@qJfh-D*_~iF`3^%4=m^1$X#6AQ2C9zmX9j-EqSz-dr0bfuQ zX{yhQh`7@=?*Tz-tMQZWT?~pRx%{vMWGlTK*F1c)5xECQHd^XDYr8TPeL;f#nx6g7 zLrdEsD}R4Z2}xm{>3`_H(x$Y6@kyW8yeB9`bHJZ*Ae0rTtO?&E^Y0G4)Z`nopEj4? z_=pzmE|#y!2AI;lahaGX1NOsxB_(`}=)(U1s5`C?nL}1Q-betn9Q#8kkzBm&eqb^~ zW0jKFM>4vwUOr|$pn5a?aFWoq?UVB?RfQVcm0y@BYga+H5bs3+l?ku7ENml+rTwsN zx+n+V{=yrPXy`bM)fcU8D2}$!J`T;IResjvzdZYDm%{aO=Cpk6zI>EQm)4B)es?ht9BUulyJ7 z3d++3I;%4ZiUq$_EIL=tDINPK%>-YkbM-IAwVu;JouIn>&6e``9G-hT*I7rgEP~_* z9?8}QcPLcv171!#R2)}Rx@NL?$A}OpgkQ&&qy#q_|u_Hw;2`)S;| zF(AB_3w@W~QbH0?=-WQ`E?1C_n=Tm5O;46En>nuAmMeEd1x~7mxBZzCoQ~U>fZ<+! z{{V3;ppCm1i1?<^We@>fd9G=WjIXLTw0+Ugwi?ys;j!V2^94?Yjr`PnL-Io@450I= z`+Lk~L0t`T-xmoJA?G!c61ui%ax^ohcK7h7!E>$ERQ}qtVdi18^R0u#= z;5zaR=fScn1IFkMPZh^UJ0d(@?xYLvPYW5N=pcSzT5`g0c}xP=d%U|ur7Hgb>HGXa z0joJ575;t1<04&szY$&59Q@4fi)+0>qVi+10sjCdX#W6l6~oXwI{d}3;+aChYTjw& zibXE1fjK>#d`k*m_?R5W>zK))KA0EXR9=Fs94ah-wJzClx8Q4c5U9p&Kq=>a#x&y> z3VUA((e~*Q%yp!Eic$7YYn{KZ1S)yk^=`OK*dCOpd< z$(gk2&V0t9ec>Z??KOl*fUv0M(|+hWwHEA2zCoh(ZsMuKtV-1Jf-+fn`IeYjVD&lX zEzNeRkTp<+8hSG1&G9lGxSSm4$ugW!zllmavt8WE6RCZO>Xx*6I(=NwU}^8KvSbYa z4r#aR@Wc#NFC7y;idFEp7QzCQm|?$&u!%_Tf8@9U$e#`7Qn!cl#pQRX09yz4LbT%V zeqp(+3ca#QPbIG0xKG?Qt)iIT7X8O^DH8WaQoS@^g(i49p}#-&B@ZN@EJALrSo@Y3 z7!|#1{zoov1iZjXXtB4QN{!u?@vVJKvQaruKzyy;BG(nbYSb@5W2U2tnl6h+wGr`K zQ;HV-k%baYP!G0YXr=1VFVewfuETup=L4Y>mz!Q%_9Z$by%QIIpJ?rn)!M69-2VXY z0)!Z#<2abi7Tk5YM->!&KnUct&zg$bX4&_I1Ueq#BdE8%)4561zVWcHvK1nd%ie}J zG%pyqsg2}(8NNYxdI3lui{&E zE`3V-zvO7$Lpscu_iau1P0)P<5|2&fSqHGY{irC{Dt5Q+3=j~Z)ouJerl%2Ar$YAj zmdLnDmJS>z5a8XFpC8xr9fmXe&;32(GL7WEe~f!Zo0J!6zJK1*u7X{A!rG{L>6O2z z$CW8N!ABEMoskEM%iZJ8{{SL@s=C)xZs>}D3G8eMGP)@*xu8h5D zYWfB01!RFX41LFF$h!;AzuVD!U+2v4@ZjM4w$#yu%Op$dPGECu zx@d}EZ95+(;{vJ0aaAr0l zx~1DdgyaiPxSdk38c_CvrV$cW`49vRbi$Npis$R4a~q^*f1P-RFm37b5uDICOh?xhshgKcd{uugF z_Ox1TY{1Ss#RxikiAA~`Ip1U(Qze2lIOgKplhnIX_qHguKFLUat`*T^Rrw_h43hFh zTb$k>*uM~ECjiwIZG3$tEzr4|aGmV?b%dfUa`A{iH*}rbEAtlWS>>JFGZXzE_Bc*X zx2?iQVSl}$yE+p!-G!kRHuY)%Ag=4ND^)m|&8B@QQ)+-d*v1#mveA`;Y*=X}Zk^Q~ zIhj~EH2`AWtl5m`stPxa=EJY`z+oW>2LW>7gRCOVJV>h%Xkc!OO-lQtNk);f@L~_+ zqgE*>;B|d2S%HAz6E2mzneNESTRav6!ZNL-^P}LE2TMG(A8))B0_CThmT4ariXP2Z zykdkG2!ei~&|WKi)<5I(FEifze{KtV-cG$w+($drRVkz1HHK{`PEWcy96b}WsSiuICwT!@XQpD+$ z{LByTSx%f2yJz4qY}`-wZ!Br?9mC=diZQ5sQJ&Bn5|jZ=#hJ<9dAm=EM8b_?D)6VY z6NT$jLYUSeaB}AoqpF2!8(U^_YE)?FIOY~zFIt5KV(l_{H;v9}UaqASQH^46v7ES$ z>Mz7~gBrw0R${l6hO^n4c*ms@&r->E#K%c}rLpljxmW)Hf{r6yCXG}pq`uP4Omvv- zF)%YiN?F`kOTNNfPU zge?6;aRKsN$N}J~p8kSdQWK?OWx%@?FMd!kz@>DlLxS*4>Ul0uPy@uepuU7k)c%h| z$gUYt#KV~PMw~IZsG?MD&Gw2Cs0Hua66+L}wSauepfvAg^_Nu@b(lDS8>GC&arLD? z*7Ny~{5PJF{{Wtf`}{x1=jXm2^FJ-!;qM>raEU)l{DA}nZotFo3d9ds3c*ufO^GkA{ud3r7SZ_qJwZ&;-X;r&^T zfs}r`m(*_OtW6{v&L2{(OaxX6O>~;{8As8n@Xul)S|T+hYq{MqHdF}r7`Lu zp?RR1J!RN1HeI{7K4XT)i>kBjhc~N%tBtHyZQFf`iWHLSm}CXj9gTAo z5+TB!ms{kiZm0&BV)EOM?#9C4tp5P-rlhZlUhp}Rz!%hTs==O;b^auV-{0ayqX62fO1T{8bc7lP@2tZT-F*vV8 zID|1#B6N%fx1>uN z>QW^kv@XSO++pT+7K=hrdtLM(t(-1uCB);$N}dJ4wINOKM&H4U<*!KL(qn_#A0 zHd2E{^8`56mhQxLkeIyT-FNxF{=}n-PhKG8jiL%V<+_c_xNwHE11YUs~U;Eiy>?3u6f-qSQjy3GYSA7@*MD>7hH#J5<5 z<4DlBIDv{~n}SktD3p3MTuYcc`V%5rlpR~?7@dRPqIN7Rd1A-GWmlkP^I+3m;jiHU zclM#($5s>n0BTSdRycc@?ZTCy5JR1SQSxVmNR~m_uLR}6L(WYns5KyJpB?FuZXU3 zs>|33oJ3qi=G3*`Tn|X@K5f!)+M0Ucih>VJkRe_W<9p<7u&*-g@rKI)yf2T4Q0T$YR~s;O!451d zP&~8J?p1d{cXaY~h9)xsP+J|G#Js+M_&@OA{{X^Y>edy^_Cwu)*`Zag=0ms*;By-6 ztd8%C7w0kb?%QD1FQJfj;!?b6!pK^n>Yx)eQ+8{Wp|=+CUf_6+WzF7o{{SL{;Qi@e zFqZiAfHdc3E(i0YHaCjt`mg-7=4r&TEqY}X_>?}G0q9=<^gW2Igtb}%B7-c-U3d;^ zCT`F!JkiVFF$JUm3YOXo6|48TN?205I5J~2wVW{oCm0#pwil)V03rAyyX^w>!8FV_ z7y%H=nUyH|AJTA{o@P%)R^mz+n-l=>oG0Q1Dr{nkkWv;|TwOzG;5Ctv>jkJsRt!9x zbs_S=X<2HXMIP|#)E?9HbcQW*hdVvjj*v_)nvCT$PnF&+l|yA!1>+qK>z>l+G=s}d zpJkR{Q(^v+s<;RelpZs_3nmK#vasY(m%2;zCHjYQDD?!tPJ}jVH4enw;G9D!&=((F z`C@YRxM5x~!g@SI{lEjhp-2dAZ+z82>f9l*jvW;BGumEu4bcZVy*h$*zy~hJ<}!uI zQM0d_jw^T1{f3ctPHKz(xKuJNXA7?p9wMto&K`H^CNnz`9U>+;gti;6{51an#cqAF z4Zv=Kyfs3VmHT(l_pytkv*{0=$ zwV}J|{kh$WDZJlILk6RjWXT*o<5FWbq++d2T@LdlmK&+q^lTg&^{eJwyoA0PlhUpn zP!8^id<+hK0OnKb1(nxrT4+12B7`OcEWXNUtX)Hm8V9j;bu@x?qvkq-pgfoJx|er* zK-yFVsseK}_G9$6edf2`w^KDda83S+)?;cIvTO`H8?NR;zT}a&A(~r--+RqqLD2~$C6=1~iAbX zh31BE{{SF_v6?d}^Q=OT@)Q@1-7@)zfJ)si8t=M<&XUoqIjVZ&@in>cw+89~(EPvb zDvBg&N+X9CyhmbKkOc@8#L_o$wPJc;M2VTgYd=^>aFvWojZ1i_29d|yVsPiB4_FI9 zMRX!&8orTWBCgpgUH}E#biB)u-C@O^+(n|;vEEuw6DTZ|Up)R{+rXLWD>~J^G2K=| z$SZ}WQCw>`3BhtXzI~yH`uR)GQ_OY z6RZlj+sq6^gKzLIea0LRMy~tJR}@-;!edMqPy9On0K#}6FDk#F#NSAJ zvyZRL!Y_g>&|+9FAYg`O;NF5y;GMK0t4RB)$`X~zu*w_%0M>!< zpNXCbY6sK{hiSAoHe9b{!+Dm{@~w%Ej!50GA3Ypm0M`exRT7RYyXj&&?aUwuXt8Z| z-&^*GkkH7%>5GC@^{mos6)_QZPaTbW`%6G5v3I{dAOKWCE*TEXzU52HVC^Xb;-X&T zQOSMaxO2D{1pXIH8+Y_elqA9mU?K?zlSv)A8d%UCZUE61ICO=u(h!-|mC_TE#A+sJ z?;HTh`j=b@(UW8C5Zem$dmXw^u9M0L4y(f9#^Dg}bO^K-T zJ{ey#xF`W*$&LC~cw68>EE-I95u?#)_;GtVgdBrb?{_GL9 z_$YwtLw6Tg1DecZ*|Tksr8l;+txA7HOrFoC-^7uIbl4 zVB1+%Is&WO0aidfw;VU`?Y|z?!+d&8em`~$(ZLrdap0i0LD_f-yc;n zUC>05P7@2fOt>H^Sir1BAA;^74DGeD7R>}x1SYxh6Rx7*tVXpk)YH+?6_J97@Om9@ zn7i2OD#c_rj3O|$TMERrQetFdXq;mfgvfydD(5zR%L&32bvoP*WE`tscLNn6rI?g( zy0FUyJ@|&Gp|(0fl)hld_q(I(iYQn zT0zG0WmN-lPYXhYX)Fs!o zhqt9-{SE&B>Xv>a93iQ^(i?`LR5rxX=!ew3n}#cSFDng~1DaCYWVowilwOLf>GNaw z#0eW#^YnB*tGN-lrEz-}EIOp(x>5!U2NKA~znN|Y5t+14e*sgrTWB4$=tiI|(3 z(fRp+!l@UfaW(1c7x4gUE`)2UUOnZIUT9P9Az*KlP>vBxLEa0K;ks)5@n0}{&S?s+ zoIK3LmPb2^yF7=yenvJ@>qzMsg(9^9RrrP`?!X!tW`kZ( zx-A}05jPe|62=4;Wqs+Ig7iTpj|S4gc(I~bKGtpUQ-@Q1B0>cMXlf5Ds2O#gs4D9$ zZWDN}5n{QI4M%b}U;7aDfuiUGaqtn>QVT(cs6{}&)^4-&EphP$-?VNPdd*+2Xjtxb z#v$PXUh3Xq_fVj+k1%~pvW&8%V)Kj?2V9rh0Dzzt{p0kNc^)PZRfr#jV zj4&-}4G6jLJ3OlZM8I9%c#lxrAW+aYQ8UfIS8 zez9gRq8dG*^oz1h^0iUqSF}c)M$8_|z?h^@)j}oO(<&Dj?dF+sRZb19pl~aDaYo(- zI&Z3rtcVae4~!~gEh`LFnG>Q9XGu4@BFSBL{0@Dg8%GYc`O~-MT%_XqkyuvpO z4?)T3JsYWLw|Xa55d#s7*?w+`CW$~b?E+4$FvEtRm%5eQ11sXX zYzu+`b$HBb>#;y%kr5v7N=UI4)nnlmt2Ec$$osGuxQKi+3tnW@6{Qv!?d%sUGjk0~ zai322Dk6=#{{ZkPa5|?0)a?v_!BDAo=LsuY#6VEliX|?Sj-V|Cr0s~pG8<1*3K6U~ z08OkbUu)nt^0)l@B&JjU0Hq{L;eH^O3Y$d~9L*)So30X*;g~{#>L7hX6~0#iOy3lP zo-P}o@lPUg5l5^B9_}N*76@G9p)g$4yppKd5Rg?SwO5Yv`M88i-z6@JSaUIzq$Oki z+#2Yq_!-lJw~gGUmEo~mi%4b0*b!3MPM9Tg=!(Qfqqu4USGD@H?0OADh+ns%`;{<6 z=wxf89FO~Pb&#UVH@>5M9L*ga!<-iC&C8EDI7ZHD!CMejk8=qLvq3JR7AIWRKqv^a z!ujJck3uUc7q%imPbJQ3>7lGf)X@o?j%yCFgW3jgTDe`@Sh)H`$^GIFKf{aweBv1e z2RaIm_AEw>T+OAI96>6-R#Kv8l`+tp6GS;@l(XXMIx;BxFofE;(z9>R+!l0gcH3WY z0R%7!i}%DUHGr#30F*#$zw@hr2&-If)!&K%m=(O=;W8FLy;+3y4_|r ztWv;GtISBk&X6xPOuk{TE9G?XknHe3xR2R=s(%lnX62fc&A;>^Sv?+!sJ#U^Jq4x- zDq*u?{EJ$G7nPZKy4SzlKthyK?g0E;J7|A`fiTz&g`Q(V5^yjq4hjztEf_<_D(?Eq zgb*p)NwMsd)=5Rf6lXRRy3L4nsC;x+l-O-stp zPCxW!?>>u|>%4ay$DBb$u&0`854BaQzzg!Rxsma?U>))Y+)5gZvcBj!0dyUu=Cm7) zsel(27eJuI-~}BbjnjNV!6Ys{`Ql(Iuf+%IEMfH;^A{|AO1&LaHwT$%-Z9K7?+EHj zE4;S0)XJm)kPwK)19mtuh(=ye zYmMG~M*snA<)9ebc&@B$DRR1ie-EYRqrXEN{{Yqxi9ZoRmzw&6FZ4Mj32~t}2Q20fj^y z36GG3RT&T$TBWUfN8$3uDh{y#D)9--#Wa@uPk|*}fLYW{nW})3QYc_6IZ!RCdDY>GWKt;Lnte|* z`yDd)I{GZzJ&>Fx_#iIrxfq1cHWxykk1YB^{@3?06PaL39x#*b=xb zWsH{xX2<}_8QQ|AR4y7^m2V)`41`_-7o|s`< z{S0U+u%&Z|13yfd;^pel9I)fMr*j+*HTO_Z68TjU!m@>a89lEp)vp z>a}3t$9OSxG9cmvIYLn4&Z4(d(=sL>lz!CNntM0s)01$ya{i5 ze+Q5M01(bPkgErEq7nf~MN$Q?nUMh8sI9@HlmnmY|5MdaMBtrf88pX!HIRH2OASG_-UY>o?kr8jA2Ius%BF` zAeIC4p`zb)Sf!Csh@8eBL1WYk_JMbZL6ksC^^W1Gp0i90<2%_+`x6T*5&*TfL-8m? zvudX_BK2s#U@qxYR`%lv!3O2%F4}Q=nGMHGhQ8Uym`-S#hzZjAoe>=)aqSjci=-n; zM0Es3aa_&UsnmBg`j>&Rfa<(JyB_0R(ACiQYcO7A_|Sf!2?Vj^?R_CKW?#Ipv9->x zj$$i_3uib-t^G>Dfo1N^W7~*mD}W-H0`q7OxJ`3jQhp$FQ-ec5-YZAU7Ft76JuCLI z5s4E4!Y2I3aM%7^QqLRl=;468G09{m$VRfo%S7vT{7SG_a+@R0l_@i^iJ>fGZt-0j z#dDlTiLiZ55JycRS7W~Vo;p(&aHJSOCVjatiQQTOlmZ3i%1#upY|1YA1(O zDSNC%2pD|NE*5x#v~_}p`52hCaxCXgYU6se6j<`rP*xzlMpRv9*L#@3MF^#`ETFqp z>yX)nFh*usYCPd9P@6 zz5t|+177+0y$+g^(~5fM>F~w7K4POo*PgP0GJZNlWe0}dSYT>gP0*_5VD)8s2;sJB z&ok-*NQFyi)52NoVa-tivI~0#DEXEcCD8e!hPfY|LP8~}XF&0Mp$gvF0O}_H0QKd3 zFT@<&=t7LQQC4OMGYHtW!o{AhgU`fgY9*8g)o^e`acH#kgta7!kN{0tT^q(_xAhCJ zU@PLQn(KEt%eZ?2>9M+Sl`jwj>;llsNF*D|Rxy)=g4`L%-tgl!a|wlE;_~~j{;*z` zeiNwJ$|^MrQV5NU(6TEsS}c9Zc#D3D%fw0jE}6H>FEcp2#pXGcd&fBJiS9s5HDEj< z+;OZcmYf9eB%&8gtUkNw)vO8nPpO( z55r_DY!ux+Q~MJ7Y^51Nbft${t)x~_YR&y4dzFz#DDw0&!KPUOLzoU26A0!D!i7=E z%eC%Ecf_y*Zi(@ptf#2gFMefAN?w8Jy zjBA6x)B}w$;)^~=6yAB31vYCBxN;}0pQt5EIt39tstp9avm)#M0~m95Dzl%T$6Q-ZG37UM?{(o+K;V7fZmuW08W9Z`;lNRNSD00S># zrYzT$P&MAK-Xpd`84Kip`!WvEnP18G3MpDFPS2%kTBgbUM;S-R#Zx8CY_BQPfEcF=n?!?g(>3ig8@@UtQ@L~?e?}O! zo@F*sXVEeF;^M3F0{V9z2a$#+KuypF4`^)6Dsx(6iW0!cUq!EJ&;k9QQ5_t&0HsA| z+(cX1lECrIxME*&QIu3_g@%qbD@eXOd`Ds}c!(O9j2=_xUgV_41QY?I^#LOy!3QF8 zR}$F<0`^sv;?C0c3ejgtW4KI5a^m9UWPE#0eHE)3IODz#ob)0PZ44Fh`+E$LOA{@v z4s2d`&x*W7!UIANRcpuBQ&$q8t>(bbJ#uR`np;gk02*tGGwt!QF_|nkT4c{#);#d| zWs%V5_bfu)sv@k}3kF5Z3=J`7w_B`m20(NccXRmbHIOSP2%zM04`j{ZU>X+QdLMtS zT%v<$)wG%CT-MWBE^HJcrI(%lT5*u2RGos%zdf<^oD(E++l2F9j?7r33)vfA#g%}E zG!5qZKq7=o5wSY@$!6{!h(R2}9sqLd{{XNS&X4%__>9!~cV0R{SIB#r{X#|zpM;|H zS<}d3)?3qtY}wQQ01*hK;9taXS>S$+&a&0$J?;`-UbC++9`W?JX~!K2oEat_bKhPf zkS_2X{vZno3U%fAxT8fQ_CdGS#bey)*CaL;3qWtPr}Nq(@dpuN{*E%QBRotYayxnv zb1uvk04mV6UI}P6me3FnV2xowRV+K#pY6a0KDaK+>UqQ3G7u7^;}+E!=s`s$C{sum zZsL4=6mhD`Qb<)F1epQ=CV$k*@Qf#(*N&RSs>J=4LiW@Pt&|*w;9sJ>KaMkJB#h zOUfSUc@w81aRdO;%`fSVhC9Tx1i>6DaZHFDAGQ;#vpZmP>>Fc18;sX8C~gDIZFzeH zDDki?#3wj$` zJg)Lmgq0H^D;o~Kow7W;uMM$B^{bR3)O?~ks_K#LVuF!pCsF6S@hh>ZV5fKmY*cFK z(;)t+=k6k?)1`Llujko8(v+R<_=2YQS13biJX?OyMH=X#`(lN*uSbJ|BJ_=eo{_@}*z}I>7JkoY zL@H!+cpsT>YpU5!t(X0wYR>&4piE}R-eW*4D3$D7z%7BJ{e6ORFl5R90G{<3m9fd) zW;+4%6u~k|z~IfCQ+|3%3}9Tshkap$yQ7HN34vrpHdC0c%ahtCe1(hI{cq6z*G$dw z#f~E4ag#F^?=cLiYK7)8R23o?%5S5^d4zNpOZ)`7`4a)kB0QXo8>~PK4g~AS?hDgs zqKsH%vpm`}P60}@mI|ZTzt$zRwG_Twd5kGqj2v{nUuaKM3`~O79OHjd!sKhkDvL)1 zb}G~9?i#RAQ{c$te`j-Y#$v{$-$PG9mKUINFG)pVcIExg9c2QoNFn{7dBE>Co?tFq zYEsR#d4>YJU9;^J$flz@aSz9+6z(3>#qYJ_@SS9GdqAxap~ zwV|L;3PoDGwGjh-ORN&h)-#+KMuM2D8b2y1SV{p+w^hV57zQb_cKfwVX2m_ zTISsQVV58TxsyjVZjam8VU^Etsjs567IC`95AaLK)#RWoh23bK64902)mH3I3$q24 z8j=!FY~6>w(9&dS5W!S6yKi_LKMp8R18PyRHGDQ_r$xe3MFOVFRog*9PAN1af{`tj z-4Qd`;YG;Uw_+`f22!M36ku#_j2jTe-2*ixN(#ZsP|#;UU0p4!A)JI)wP49^M* zPTBMl>%{y^Md=(}N3Vh-G|qYxo_iPdEObwRW?h+;&m9bOm9^nroVxho?H#m;Ur`++ z$i(gU7X-?y7s!bH%2!VYuETbGo#7xlvX98i0ZYID%D1ZT11nJvIkncR>oC$XTVu;_ zp_whR<~0tr>5RR)M@yW_yvmFAOHuKK&~sK}quL)Oy?2|NU{ih0(ZW!fF%b?WTkw1S ze=GVp#q)aKJWHug3Yr5e3~d#FE|$9Ui^0*=C^L;SikDbQZtN+cx~n4~mKep0D)Mh$ z)gG)cH>dYQ;gzre?~9d$!0FUd!EB*EC1h2&1<;9enbfs5gwqHt`TXwQ z*>3FRcME-9;}uc0109Nlu;oiFtH(0R+s6VhDwJM4XH_eq8$g+{ zIXg1>#6h!{tLN>~C-FzJBrYwSQ22i zbzKIl!LEgASFS`fZvOSX-s?FdG3HKA8K-OCZEjJ#0Jnz;d#a(%3MeS43>zC=joV)L zZm#VCvaKE#s!SP{pyMIOYP~wbFghK!qf&${H=Hy8Qk)yneStvMX)0Zw z1;tE`s-MJg>lT4^@9I!7p1c15A2zTPo~WuF3WNa>WrW=!5%7qHP?oju(+E{(6@yw} zDyoSh)`mA{lg96S-GUXoZq2!_m+tT1Y^JWlaf?(}!*+%nc7!)W65jYs?bz+JEHbjN zye?Ba74o&FkOY?7GOjJp9IR&A&6YY8&Y4JZ0 z8vrfw%vBcLIyesmHel;0;<__LXp6Tm?qK#Xt5MUuhrupUZO)Ngt~_a!M1TwG-%*mE z@sDXXf(?q$bCz9!RkRvT&Ek-*kmbAB0col(uZKISSzA1T4bth#@l+6ns?0K8`RR!C z3&tpT9Iu&^ZgM=X{{YC83l)|koL|FkI+$$6peH4dJ$#kOfX}k1?>Yy<>F=F92!%L~w>N zNpmXetdn6|t9}WgC}aNsu;OW6lt=e6RysYwmTs`kLmu&CPkVq+sH)$L>zd7f$#1Hl z6OpVpK-r46wBVR-j1Ib>%bfQ!w(ebO1P$HwZF9e@(UB`@!Z}vAXUR`-&;+2HZynb; zZk{;0z+))4JcjXA+f~aHFiO0wS0=#DTTbnxZgWTr0!mA*<);CcVRivqfC^OulNMJz zmy*S7uPwJ4$$_?u*xP&wmb4lbWmqwrEMNduRNLP*a^8&V7*c^?7}|n?w&+GHVg)|so{;n|p_ilaC@r9QbMvzoCoBUM+o7T6S)?2)8_ILZ6e~xX6jksIuWwj( z@0}xNo-aog1S;0iZ(thU>Q+-g5nwSwus|4AaDT`iI(?a0+3&{?Qo6ag4g=3JfVHC) zh@C3D^nq{`S&sS4B2_N<{^AE(wpFeLuVl^^=%|HLamrRaOQ?LKSh+P&M~am2ZTf~lT}&L0h}I(V zH(+8=R5gp(^6yV1pu+g9i)rKRA){auvty3|;)nr+k?g4PnitqEiipbqP1vD9iqK(Q zlRpe?bqytV5$4U|Yk1;W8g2p&

zc<3^3qv&>UgX={n`7Ac@`vmIt7ku_E;F)b>w zk_f_qGo+{~OMr3h+6l1kH)oiF+gpOGe8s?}-KE#OOKRPD_vtO9u}vfKGn8@;TOROK zDNg!$mKa$s+~zWsL#2dePXTNONbQN@P%C2VS%^vzG$YhDXsv&DjMXcQ+-yYPskyMX zz-Ho*Y$KDQ`DGltDzKM9x*gt;?yngOe-U=N7nN0xR_Vg=ky7$;jQL=!+9|fH2Kw%_ z+lo~i0Bpwsx&h143V^9TKN~Cpex}{TANYGF!sKpn>VC=L(-7#P`JyMaXt8kdf zv^EmLTAsD4#!AteQiL6#YeMO7vwONm_7zBKgg8)xT(-EzZu_lN87ly?1u*W%OQFJ1 zQg7RyL&D^14p46yxpcv3v8*gDuD5n2jf4pbf>k;B|K3BTU)^ruJ09A zsbZv+9MCDdw(P2Vt1j-1l%A6TTWG~y(a=l*iXiw$vSa`oU1000$pKhI${DCAyX5g= zqCz1VK&TqqcXT^$TydUo=n5+t<*VbQ-KC4dvOU+dG#w(74NFAEo(AGz78yNh2o zRIOcc{{SO4)XN81ftb+63jf)#x4L^o4*RblN>Bo4B8{YTd+9J?2Y>LLUoqa$}A)h4Yby{(@utKBC^dc;!G{VE)1P&W+ zEy#_wQ^^3Ctd9DGTxBKeV+FJhp3Wp>F87Y5u$ z6m}G&`0)|V7u4LsC93!{6BKb)amQHkS~j@zC_pOf>-$jJq4^HHLc#G}e8&*Mrv^p{ z4T*HP{{H~7*U6^qAN7bb7Ep`nrFO$@#Zw=dNSR9~JZnWL59F5>1w#e25 zE*-%sF@$8|s1(5ia~-tvp! z3V~Gx7|B6MRZt)n$X(SJqT5B-?(K7Jm9cF=3k9^QySH{`^JTd#E&xhPQz(_ngL!dx zbQY&e92+g16~Mj*X|qD04O~w6TV9x#zSb10bTsAO)V`d|zlEmly#8NnVTRdb*4OSo zh4`0UrG205Nfn)4$HNhtml5HU=Msx|LgU&UIHC(NzY{AjVetgj<)p|9$dADW*PFBO z2(;k;0OTEZVnrY*0j?6$rFw$!mUK6O+*ik8TQXv)J_TU2l} zi+}}XURRLkT3*pcam&%Sebe4k2f4R&8{BGG3h`llA$+@TtDF$9BnC%A#!KYG4S*%Wii_UM_aK-nx6)dOB{J!B^8l5`vk3bX3c_n@ z6=h;jZig3UI}zA&r zCcqTxleJbySFo8Fle7n8XjU9#z?NMFUH}R*IU24l6&+=;>9eCMvihk zb^yw^l}u&54Lpqs8OqhI^}TMOtyJ)b@!y!Qwk_`oSBdzRv%B{Oh`T*&e=vnv@M7=q zN)Fh7%iCWw1Je~UTj+jZg|(hLLc;Xn(aZ~Wi__eLU>dxsy3`aKz}_zEZK2gM>fy;7 zVw^#~v*sxR*~yixL#;A3oPl}sa}Gtug5Zw&6@7I3K(NkeV_-c)S(+AP%M=QQ*Sr42 znD^znA(M3m>z|m}f`IKx3hVimE_l$;0I|-6ogo8Ka?YxIFPw5p)>Bc^gnXuAVxK`k zJ}F)V$hRr)?3*Io0mAu1`471+WjJ@!-wYjXljrjo8id99SJ;Zs1_xHp%ERX1yaD@V z%>??vIH(|(umqz?ScHM4EqN&Er7F#|4Pa{zd3HIXJ%&(?F4n7B*_=NZqLFe@l(92I zb~-Z}MM-oWk?lAfW;!qN_kmJoC--<|UDEOU>lR0M(24+5QvU#QfPko+I44%K%K3`1EqY6_tM@)3E`rr% zwf_J-OTZ8zwWi}))_0Pp<%;238VauZ^G$T9X9$tBrmrWCOQRx!7EFw;W+_~bY_5oE zI(3DEFm-56+2%L^wMaC7bv?R(I&xXSx!)hV(jt^KMgw(08~(u3u7WQ>};g2aY}CGD#LAt@@;p!9_>-f zL|8=Ru&UFkRb3To6*(HoF{Ql-1mu;3Yj&oA7U<}_Dv+$z9!Qia6tTirV9|^k8~|cn z72-y2ig#2P!$yUxQpSOG!S9{Qs$x>Qh6};0m!8*I?Bxvs8mr)FrwetO^<~Yn@zv{o z^-9M~aAh3+xYpqzvChtqvH&ams116odm8u!L^*2hc5D2C7C`W0}#nv`h!-F<{$_ zV^4M%;QsmCF%5=u&KTHGG}d$RGGsFgS*$l(l*n%%Iyjvb!o2?g$zJCA;Dk zY?y65;rt`gH)<59Q3W@pj;5&Ll?O^`nt~zNQP2jX!vcXg#e-Fl936He=zqvtPzU==1GUdzbxo_N4kihOi`AM)=9q0J0aE-tm-M=To zU1W=aXi~ZT$lI_yz-a6uh~3h>Xdr_is}zS;Eh1KQg6z+E&I;SYW&p`}9HaLlfvS9D zqxF1F23U4~ZG6V6rNwd&vilQ)4+t&zWtkYW`CIu#Nzr>zeh0KsW&yFt;XB!fcOuH{ z+UZZ;R3JdR6xq=(SFsdXfT%{4ovgr&r zQiPlHasI?8>;qbz=WIxBSoK43d7s-X62Ou9iSGZZ(rUXbdyz8`nN3R5LCS7MgU8WYI^!!Fj zye{gqcV@pZLiS-8T-i<=tpM%FGX42!g^Ik`*EaceC>VlCjuj@aTwn;(PM#|kD7t&` z5-dU~VEa?t4sx@qViA+ zR1A*B%+qFW&=Q&gS|1X{)m4>~0BC?T>qS!~K?Pi^dAn2!`aV3cE|WG@Mw4yeg-~6J zaigs^EwYQPRU^QwrvZ!$O^c)~r6{}-@VIR0wZx$F1=obgQouS>}tk<>xaYKd4-)rygW>%#ag;C}2``jUF=hPsCF?ZL@!3{M|>%<*~ zfccQuzcHiN4V&kgkv4nuBXK%7=>pSuIO)WAe!Ifj2Tz-pDjGz;EE>b!eaI<>-E<&R zAsaT|;tbk!Q`?!CTjB|M*p4M+5WqBfr~Qj)RmUI0DlNE$0dyH_H|7muvAmB+8`uue zNR}4f9VajXsX3})maVp`oq2*Crg^xs^bKPdyv44$L^Q5haaUL`XWkldwa${1R+{5A zHnNH^T~G|SN8y6Bf&%cWNm{X9h0RK$DzX6@$`(5>d2MNW?5&-2YvNk<^%?=~OUgZ1 zpFmMqPT!+{@i34Z!rbGp%`x9=;L}`mrgB3A1<;!8`}S!7H5XG^$7|cfa@j8Qb2Zg{ zyhkt%AT?n5M!N56-XSS80`9F6#35$9(jo*AMyNDa52@M%ixFm86J0Nt zyfTQ12MHZ?UmcBED$?&lzB+u)rKh;VS2~8eZ)bWoh`{wTU236PbsY;`IzRd)coMY% zLtTgcmt)0W3EaOwW`bH9d;v9k?OT}IGhJI?F_HfO4IWI50Ah4%q9b^tW*MN~a0Inj zDeB#6lr$1j3@b?IHgePB8fK$@AkHREqtKSF)5c#>?1n_%y$+;_tEtyeE+;|_?wMWc~4!RWZvLXBn#WMP$#u=`AyfJ;ZO zwL3GUMn!AzC31zg0VpRS=y*$=QC%)uqdDN30-f@LB)M;n;zmFXxR3Ew%YjDmUJ(8oilI9|wKVjv%> z)p#5FmSGSrcfp3@oL@;p&?^Hd5}hS(s#di-$(shx>X_FGRI^ju^&BA?Z_(c=SHv?1 z7O1n^a7EQ&Nl$y$KN7ksn{5rX?C!YnE;I&8JXM^oK6@=hmnN7uXCCm;4!0`(cbG{@ zpJ}AmS2J*W0$&LypU#-(JwkYZ#0Q9Dr~#STn^Ya~3H_)QZD*8+$D?Tl*xg~mp;gSR z5b}K@wCd^jidnBWYfD3ctFIWi`xtF1WV>E8=f-gE0~JB(NNeVpoB>`M01i;34ZQdr zTw#G#tEa>WC`U<=k3wC3xP6cQD{Q*S>!RF%p`c(3slJ4 zLq(?p0CT`O8UUv)o*cNyqNM`1Z#2}$3gM!)>TQ4MEXpWN7H1f1Y#JU#nT|uNk zQteQ>PH>H(j6j3{7QnQ#DSuXz^;v^5N*2lyh}|(I4HnTwt2YP&<+}6SpBD5iM+X7f#ww(DX+SU4*fXz?!%us{g9Mv7YI{$q`Km=-uf@<&6AgB!gk zghFlTX(}cddP88|duhv%HCut3P@`xjvZ5lOy>{AC-t3e|@u%;s|uL=VAgZRc|ph#J8ba$9lR4O3<+!F5ZkI%*P$ zP_9W^FmfT<0IVwTyA(p^+-kQ;R{CXwPgrwwi(r<%N0ws;3lg=VGQX2@v_vTwI*&zr za-GlNcugUdSOYU%=2G&#CC_~JBFfZY6IYXOHkE^SO{2jQ99d*|IRnLLLlv@h>@psr zom!6bFe)bLY%=1}LADP+aw6T*km_39#W{qion3)VWJH%5fimr&)^7*~c*HYg4el-s zc5sd?&KTtot(5PMGY6rp93&-FNm0~wnAWB$rEVS|X`VA#+ZiZFXzfv)z*%WzEzlO$ z+O-b2h;4?`PC0%+I$q#zl~7sN0B5vDp3rv2?G`)aY(yS+x}FUq)Y#Hbvl6lN@gLND zT!xHLb&kBjZufO!9oC(j_L&Ks7ckT?^fRyi)D|(s0tcay0^nStW3+mL(Ne}cI0A|y z*=PtZZMuAhHq0>OL3FJy!+el-S!6&a_s;jmDjdS$bOu1hqgK!r1U!%|&=nZ0^Uc<$ zDR5zssjIg0ZzV>YHMv5Oa)I%mXeu;vfYW>#_SZrrKpI+FY^vTm`$64ead|4i!?h)d zifWDK1)d^74kpk~>2zi}!UFRP600!koRdOWM%xzlvJZK6mhLg&X*ZYFT1O0p zIXd|M7F87mR${f|nce_pjAHsKjH&g$o&Ci=!3!mECr( zh;O}=bL|X!2T2!AH;tEN`^0+KQJ8m69EfHOt5#=4`qHQ@j zO!VhFbkwc_TB4^zISxBSTX~j24a|{tK-^73xq8V)==_EzxCHfF@xte1ifw z=)W%j1ySPEe5=DO1#7es4~%{w!^{)6v0w5~tOIBBh_vQhDEG!sc=Q2uwRe5>3G!k5 z4lmq?PD)lXcHx|pI5#tE_%lxvyAjB|3kNTz%3_?4^KTMga)SAyo zssp()Y`wAX;vz(6E`e)~37!@MMKn0~eqw_ttRe~{p|R&(8I>f!x*krf*~~>E8^`z*{^R`}eZm6#*Z z1}%bKWjKM{7Bbt6YvMB23MF^iQZW=|cKxc6&4i>5d1~{}I{qR^v~a2a0A?d`Myur@ z4T6AGOVAfiA%~lU*;1TilC_>c$aHq$o7=zB7lp2nq&o9q^(+TEmH^tJ> zf+N!~;5`BYOSQGK z>XPeGGDkwuki(*ir`bXnwyRJsLA0{Rd{h7tqJ=M;Z!N!EYBwTDk=)-obzOF|J0PU8 z>a%82nh(gV?yBk(rBc~KbSD*wQ7LtKd)G;MvW`GAMpB>d1cqmui@;vurl;R%p7ep_cCT}mO8-Q$8u8&+mvs6s&Zy83hy^qZyni~Bd+inH}4gcKw9M31)jt!@sMOwy2dTznLsB3!1UJ+yGM({RB1K8 zX;y^G2#*I&^J^F-mQZ!AuC47Eg*)6GM2LYjf>7KzhZpxqD=2Y@Dwf170<6Qzz-dYY zZLAL@VRWbmDWaTPNqFclGQ3a$alWu!=w4ar2O1}<$lMjG-H2T^h!|CX276SnKoyPZ z)?z}=xXj1`t@Ys7<~t5l;1#!=XFe}6O%Rh|ga^IguF>L0a8+oXG1PmGyiTG!gPFAD z2lwe`0$_)x50*953tn+iIW-x{)pj_T4!5GYPFEcWB7^{{YEbkps5dgyd&5NIP?iPG z9Sq!dC7S9(nj)&ra!Nl(?CbFq&DS!$MGKIiJ#ZO}hoDjvM~tMS_;Q#CAn65@Ns$P0 z%U3fk&6&ZBFPTV_YC%^BT!u=kzc9Igu++6spif{r=H_h@#8aREw-=YMN`t5XMOyQk z)Kpk7-h=T8FjZ55=$#^*qF%8~DJ^d=T=2@GtkUcNQJZS@xqEEg1Uoj;mri=>mFwc@ zU8Mzt#a)F_qUluzjfw>*rRk;;Q%t-pd%~TmI=Xp#;0@EoceBInG*D#;|1& zV5W=HSIn&t^ng+I=tPMtq%d0vKZEHlNv3a=zM&dcLRP3+TkyxK8Y@7@o<1R0mobH_ zZ+j1(lFO?I@I-MHFC){mr!(b5;<9(`{%c`jM0vX3m^+f#dE|c(+8S|%%^j0Xkc3#Z zp0hQe1i-AXCS~1AM%9sd5&j`TRUy{823GmmJY zmH_77(9#x%3yX2@DIlT=AjTl{Kg-G-2cYfhh9Go_Y`n0g29qkCZ=n>-7`(usSS~N6 zj`i4$#7ae8bR6>?bX{qBD;fh_LQfVglJ*X<belE_?wM@cw6G(LSRT!s=&s1exX3Bg7$!LED80C@jL>FGOdLiW8sYkTMpGtqIkVk5nrK2PI?LT+_6!C5D8aP+UwkG>=M#uiv^Hx6_552#I#=~ zGYmzw@f#I_W4-1bg9~;orzodq4NS$a0dlKh&;;n!#z!gm(w&RJ+fiI7f;~oM)bR9D z{Xf>|%@b**CQ(xk$-)B1G+@=5Fg_RJI}W+htYc`ft2N&fdtqWeK`(~oj4^{bP$T4u z6L96JU1ILS)AxUv3q>u2KtNblF3z&I^mpL^19=PRyjM*%WZC6v59BRdTUr*aZl*iU zzxWcR$fk$$NmBWg4zTKH@g7p;yg+HbPOl|>pEHXPbRcWC$O5^fcAb9XGb-BjKlw1E zuymp8(rMUr#kIK$un0I(rd3>y{(63t~drX@9LmkJ6i z8B&J)0uyvc2d+UKszpY>uQv$b!e{1)%%7bfC}j_)MQgP(vR%Z z76>;ME@e$ZmJ>E-ujzuw1H4DEU;@)bymklz%Upwj*vF%P!LAkU5dVH z2$oS5L2Gv8&wp1@YCE32Q5pO?OGNK3hRJz2Dm8HsHL~4~3+|3JT+2vL)VlgF%F4!; z4K39L^X4>XKBAj*Wy^tv>!I@k z*di>^uth*{@fK((8>f-RJ^aU#(rW&o>&rY?s4zH-r3C=xuFz3gY@)=A6N;!@%t+bj z5MhlOUA+x80~1MUs907cq8CpV6%;X3dC1qhA7({ehl-`wxflWq#$E!1PWN!KFrhM( z64A|%YN~G$nbqaGgG#_x-HHpeGi5QvGzY!P4S3pXhc%V*#!7HDTy2}1TByp059QF6_6BY_= zyOu1hqzmp6vU(b;f}@uI024dOKzTC_Fhs-56av@G#{dfO_=RlFa# z2CEyh60i=017S+*Z~$S?GX)?@r&Z~MsDND0wCPH>Hk11vljJdbTpcf>?2^I>Sdfe{ zgEgAO5<9pZ!8}vTX;J-3NEUKcpOq-TUl!N z;!)@Caikq6Whec_6;e<$C6kb{zVFvw*2Ou5)0ND09w0yuIX}1W% z#?zjeE9y4HgPG0YpKwu$+>=xy`uU{7iP^H5R$E4=C zf+Z0D06!^8JWhyM#RoH?1umIvLFytgWq{_3e-L{xSZLtb$`uJZIIFBX2nbzsqYgr` zy--TXML>e&Ji~c*gty*tLg5H}i7@3zIV+m~PjJb0~>qG<;wrg-ih@ECJWNK}8@NY2zaNAkp zmsX8DW+TOP^j!hTY(wf+?j6E7wAFKCDj7hyt$C}&3d5Ixl*<{y^hPk0lu#Ce+5?U9 z;#eMq?8!OBzehPz>R(A>uB^VT&Kra_#CpJtE=q}VCt(`QwW#0?b;KE`)$=!hiDCyB z;Z?z{<0iQvNEoJbG^5SUeC zSJC%`fhePgkUhR*lX=XeSl8io^$+GJw-4I%D0deTuSDh?JtKyr*&M6YOv}+#Y(Zjz zCGe>x7>k|4?Iy9Gn7oLj1gw|Gm?oJh0ChR`eWG1$Uelm138@nWt=}+QIGJV!h?Rmm z?xpI0`X5CynW8Pi?-A5*)9ib#9@Nkt?NXk<9sxSiC=@H(5nq@ zDal)%6Rj;nn1b;DLaaxw6EGG*fD3kM-J6QRHfn1bc5xP=C{~Vt*d|si9wpeL8wRwx ziI8=xvA3Xo9`VJ*ALP?N1PquP=Dh*7JVClW4i%O(sVUl5OSIKa!GPxV4B}Q4Oel8x zgLDuztPYGIzR7HuG*n8=crlA5W#g-c1(eA`-8C%8k=Qb9D{awNRR<{=)GQahRivge zR;i@5a4U<-kpy%jc))HF%gomqikRyYJ3pZ)F7P^yr!bP`*>U{KUusTFKL|e4HBE5f zRlAxamI@fCw7T*?5d_FxIactmo**P(la+PtG9t?bDz?8fFwmM~8$ICW=FM}B^@OsO zUW0+GoN5xi!fNWCNs}n!Y9%?j4b9+#0!CO0}}+|AnqKU zC1O=#bLxa0B|agujmC7mKNQ2QDpOr76@IuXpM?77QCICC3o5Dwm6cFZF3~g`nQOM-~z1GmJB0 zjCWGCf3oG0q84TTE=yNPjnqAL(xC3!LbcG`y|t#!>MGx8uO6A_FsHO0ydaP9&XH%6^)yXTl{ zMJE;9>2ZNWy9N1k;tpAqF_hvN#p@eIix2Zz@{BpeOYJG~-e8x7oJBD7cx9Pua|a?m zFTzEg9FPfkwyATX2x7$AUTVO^tPDwMY?(EL@1By+9jUWXuikHnde@PmO9t?-Pu?S8 zHlUPnt<`XG94k1$3(r41%JTzO!P)u$03svOl$U(nIO|Jv-4_aTb2c)S8UQvRD1&n7 zfF%H691Cjl?SYG#x+`ZnfpNsJeF(v14!`)OP$f{q+5!H4BU-P49Fp{SNRCXaj*^o; zoYSFvXy4>gz&jha!QJKiS1i7r-G%Ed%g>LL+1 ziE;k`Unod;Ap^`$K&LVE7U1*5qMRi?;%$QC4Z!jX32iMiSJEY!ikbwH?GRL#oQXtT zmA$I~)1M;&wN(ky47JnWC64fN&qQ72S8ID&Y3t8+6=`l(->CMmU(GfjEk#Z0aOz)P zlt^rkE{K0-8KcoSOEC_wsOb{wQ;$S3F&RjZ46vDadc-z4ZjtY%>z- znxqu_2p%6KtF6B-rG>Sy0YwG0sm8!W&5=Y{^e8a(9iwwK0j6c$#$9t6L;8u<4J$6R zTVd8)l{IBEWjkvYc8ppE8yu^6-yBpJlqk-vR^4lLjIdUlRu@{XEq9CK+6buXRIFHlIhJ%ifw(?yOi@1i0&bd%tp)vNP``jclF~f@-VYA zH^kEps#gSR5nRBklB{+XmrSXm4w)fS@WEySs#)AJy);vhg-e(w{w(erf)i#d4Ws-u{bm$1@-dGw%cLmkkSK!2Hgt}^uZaf(g zX-3lc7WKq!ND`EFS_e%%r7iAU#W8Ep$tv`}q~V30)1f+$S-no=D*7u*GQ;|;D;@#P zYOltLSYcBj2O_L%WT5ggxHeZg3O2VCN3MW`#lX8!=}8FU24tWB{t zJvElzdb*Ub$kLyil%TB`bQhE3#9RGL7qV-oh@;6b!g1W9Ern5{{Z_mT(p3-HI)o`fZ$<;JGT3)p75UV9^LLOo*;sX z2sS3fnng}yW?01fUT$2Dpj5GjK*64nA3`unAX#RVbqb^Aw+!;mND6-5^$CLt)LNje zl#ciMl$!CFM^x)EJHvX4K&`gKGq?gf;;J~sM2Wn?wu6P$rB!5vd;lebgn1y5E+Oe{ z_0EssMTA_OMG6pvGaL!67v1Pl1O@3-2ewz(fGQ>j-Q_+d^{vI)*G+9WUCe5M#Xt(C z6E{4z`cC@m08L5XB^>hY;%XTPvQ^UX=5D^0LpOEWCqN3deh|)K>Zv(=z5f6b!OY!i zG;?;~I9{Rhm{3qUS1*kAmIR`Zq;dxxnk(%80I{2nH+q+7wJc?>w+^zY*Aj#gYtioRS}IDW zo;u60ttM~)dyi;jLWKC1B_$I`T*NP8sd|MckA@rTW8ecr#(Q%f$fBaT5y<(Ah$5t@ zpV{e|KP(5Ej-xBYN@64F0x)L=npXkg9RC2wtyy-Xr7G_gb}c+iBnI>f0FBc2b*^Bx z=x|{UDdUG#64EV38L`r@7Y1f8AfVV_ApEyA=_LZO*OOW_5WyD>A!n7Pvs z#yS^}dnHU){n09XUur!rEYs)>LohB=4Sz;c0T5#S1-Lc!g;MH27;d~vx5PBU7 z2Vyri`t*)kOiSL;ue}5D@<+m<)y&as{&={%9()4Mtzw;(R|96t#KXEeWH_l!Cj|-} z?=!7u3Oj9_uq0bMbo|VF$zB~|f^1}R8?7VwK>$PtoW&hoQV&b$?E56^+F558%IxE! z$GYVa=!+LWhT)kd64qrj^o+@A^zU2;R|ha4B3Z|U8$B57d{w!F2pPbrv5`U5fTN}U zCVGo*ZOae>&mq|TLiDD$F`=$uWh^uR)$l$D4MCtZ9wI#E&gCU~`C6YAwbl}@4r#RN zFiwK0Em4x6-!Z|fh!$rU_m|pe0QwwHob+R1dMt+rC)?Pvx!8iE_2aYiQv8ys zbl{z2R3s&-P65?or4b=ft26^Oo{XeOA?;>_HI=6H_(gz9>TTyd)up{z;IGOQ0YtQg z8MLpiV%U~?31CS@kghK?D9Fo&1U3nqp$kn)CrScXV-APzKj99aEC@BC5h~D*F{FgX z7^$Bt_CC|G0xju*eXe61BhKTTOM=Ljrt=uu=YC*J*F7tsGQEM1$P{oIyW`_MSy^V5 z#d^BS-MGnZcIe#>gk^Lg^}_%LKp9|e89~~Ewr`EftUD@;E`=iJ5Y<}B?MO6dNuaf&T^VxLCN(qBH=w! zYbf-(VC6Y_ek+gT2fY*qh^@;+yR8v&qyg2cis-BdN-4^37H4vw5YcW}d1Zxs;@IxP zM%BiRVU}UGK}hKl$ln|?pkGW3Qu}|%-~b)Cm$e!&v8FEojq)ylW>gsv+a>bH|V#9I})l@3I_#; z;ygL)kxdzG&T8ug(Yrq%h?kWKYiOMUFENvTu)5eome3il9L##NEPzC=ZpR=~)~hNx zKpLRM5~*7(;XxRIKobDhJM#-`mG2oaKuS5xN@;5zN6g&qm8+q7J(3>Uqi5?{eZ}X_ zJ3N~`;e1qTX(*?}VzQu_R-h`?T@^0E7Pa}InswKigwjy<0MG|On3Z5$AKri1P4i;! zL`#>E=8x)9+7AJT#!m3dofl~T0FmW<>*ZQJ6kG?aZratEL2CiP-EOORd}K=>h~jcb z;mVk0VB2o0BB1LfCtmS}3xH75(~U&EG|PKd`4ZkI9?V3iVmU7ejuNp>7~`ari0-#N zaQjO5^;MnGv3VsropC%LlQ9(mc0qS>vLX*#)4^}l@SY+Hx2w0_H)%^yRaP88V@2Oz z?ZTYWYNdEyTe82j0T(VQ&qg4iW)^{KD}?Lj8~Gy;{kikLdc_)1uphCAn@v^H9(xOVxxpeucybTKJuk-)7Zvdg`NX8;|VJi8wM0QMYHaY3{bi*emf)({A* z>PP-h1IW1X&x99KIoL2;-a39@lfn={QnzZFGUKFuBnDL>L(svF-q89A40wQ6iX(kP z1F_cTRO-GglrxpR=?~mMh~}}^m?&N&vdNOAcbG8h#p7jVj}B#i6gI3X?S@+a0Nr57 zI Date: Wed, 19 Nov 2025 16:19:57 +0100 Subject: [PATCH 123/226] swap out to images --- frontend/src/components/Auth/AuthCarousel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Auth/AuthCarousel.vue b/frontend/src/components/Auth/AuthCarousel.vue index 0099d9d68..2707d862b 100644 --- a/frontend/src/components/Auth/AuthCarousel.vue +++ b/frontend/src/components/Auth/AuthCarousel.vue @@ -5,11 +5,11 @@

{{ $t('auth.left.oneGratitude') }}
- +
{{ $t('auth.left.dignity') }}
{{ $t('auth.left.oneDignity') }}
- +
{{ $t('auth.left.donation') }}
{{ $t('auth.left.oneDonation') }}
From 94a780061975e6c9500ce6ea21d12a34645dd51c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 16:20:27 +0100 Subject: [PATCH 124/226] don't load images on mobile where they don't show --- frontend/src/layouts/AuthLayout.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/layouts/AuthLayout.vue b/frontend/src/layouts/AuthLayout.vue index e9f0aeaf7..984c93870 100644 --- a/frontend/src/layouts/AuthLayout.vue +++ b/frontend/src/layouts/AuthLayout.vue @@ -4,7 +4,7 @@
-
+
@@ -134,6 +134,7 @@ onBeforeMount(() => { // clear state store.commit('project', null) }) +const isDesktop = computed(() => window.innerWidth > 768) // put project value into store, if projectBrandingBanner query don't throw an error, so project exists watchEffect(() => { From 4b2f5c9c3d581ae846efffa5e46b21df0e862b63 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 16:40:08 +0100 Subject: [PATCH 125/226] fix style error --- .../src/components/TransactionLinks/TransactionLink.vue | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/TransactionLinks/TransactionLink.vue b/frontend/src/components/TransactionLinks/TransactionLink.vue index 9ec81675b..0cadcd28f 100644 --- a/frontend/src/components/TransactionLinks/TransactionLink.vue +++ b/frontend/src/components/TransactionLinks/TransactionLink.vue @@ -18,15 +18,11 @@ - + {{ $t('gdd_per_link.copy-link-with-text') }} - + {{ $t('gdd_per_link.copy-link') }} From a2ee080ed5ba287e7bb8bca56866d1fb037baf50 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 20 Nov 2025 02:33:49 +0100 Subject: [PATCH 126/226] introduce redis-semaphore along with a running docker redis server --- .../src/graphql/resolver/ContributionResolver.ts | 6 +----- .../resolver/TransactionLinkResolver.test.ts | 6 ++---- .../src/graphql/resolver/TransactionResolver.ts | 3 +-- backend/src/graphql/resolver/semaphore.test.ts | 16 ++++++++++++---- backend/src/server/createServer.ts | 5 +++-- backend/test/helpers.ts | 2 +- .../logic/settlePendingSenderTransaction.ts | 7 +++---- database/src/AppDatabase.ts | 16 ++++++++++++++++ database/src/config/index.ts | 3 ++- 9 files changed, 41 insertions(+), 23 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 5af152090..cf85683f5 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -43,7 +43,6 @@ import { import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUnconfirmedContribution/UpdateUnconfirmedContribution.context' import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' -// import { TRANSACTIONS_LOCK } from 'database' import { fullName } from 'core' import { calculateDecay, Decay } from 'shared' @@ -61,11 +60,9 @@ import { extractGraphQLFields } from './util/extractGraphQLFields' import { findContributions } from './util/findContributions' import { getLastTransaction } from 'database' import { contributionTransaction } from '@/apis/dltConnector' -import { Redis } from 'ioredis' import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() -const redisClient = new Redis() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.ContributionResolver`) @Resolver(() => Contribution) @@ -440,8 +437,7 @@ export class ContributionResolver { const logger = createLogger() logger.addContext('contribution', id) // acquire lock - // const releaseLock = await TRANSACTIONS_LOCK.acquire() - const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + const mutex = new Mutex (db.getRedisClient(), 'TRANSACTIONS_LOCK') await mutex.acquire() try { diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index b6abcb0b2..475d47150 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -32,8 +32,6 @@ import { listTransactionLinksAdmin } from '@/seeds/graphql/queries' import { transactionLinks } from '@/seeds/transactionLink/index' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' -import { TRANSACTIONS_LOCK } from 'database' - import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLogger } from 'config-schema/test/testSetup' import { transactionLinkCode } from './TransactionLinkResolver' @@ -46,8 +44,8 @@ jest.mock('@/password/EncryptorUtils') CONFIG.DLT_CONNECTOR = false // mock semaphore to allow use fake timers -jest.mock('database/src/util/TRANSACTIONS_LOCK') -TRANSACTIONS_LOCK.acquire = jest.fn().mockResolvedValue(jest.fn()) +// jest.mock('database/src/util/TRANSACTIONS_LOCK') +// TRANSACTIONS_LOCK.acquire = jest.fn().mockResolvedValue(jest.fn()) let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 679d0f644..4103a8a7b 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -50,7 +50,6 @@ import { Redis } from 'ioredis' import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() -const redisClient = new Redis() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.TransactionResolver`) export const executeTransaction = async ( @@ -63,7 +62,7 @@ export const executeTransaction = async ( ): Promise => { // acquire lock // const releaseLock = await TRANSACTIONS_LOCK.acquire() - const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + const mutex = new Mutex(db.getRedisClient(), 'TRANSACTIONS_LOCK') await mutex.acquire() const receivedCallDate = new Date() diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index d0bf08b7c..54adfcee3 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -22,7 +22,9 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { CONFIG } from '@/config' -import { TRANSACTIONS_LOCK } from 'database' +// import { TRANSACTIONS_LOCK } from 'database' +import { Mutex } from 'redis-semaphore' +import { AppDatabase } from 'database' jest.mock('@/password/EncryptorUtils') @@ -35,28 +37,34 @@ let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } - +let mutex: Mutex beforeAll(async () => { testEnv = await testEnvironment() mutate = testEnv.mutate con = testEnv.con + mutex = new Mutex(testEnv.db.getRedisClient(), 'TRANSACTIONS_LOCK') await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await testEnv.db.getRedisClient().quit() }) type RunOrder = { [key: number]: { start: number, end: number } } async function fakeWork(runOrder: RunOrder, index: number) { - const releaseLock = await TRANSACTIONS_LOCK.acquire() + // const releaseLock = await TRANSACTIONS_LOCK.acquire() + await mutex.acquire() + const startDate = new Date() await new Promise((resolve) => setTimeout(resolve, Math.random() * 50)) const endDate = new Date() runOrder[index] = { start: startDate.getTime(), end: endDate.getTime() } - releaseLock() + // releaseLock() + await mutex.release() } describe('semaphore', () => { diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index 5f3bb02ef..72b5a9a89 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -8,7 +8,7 @@ import { slowDown } from 'express-slow-down' import helmet from 'helmet' import { Logger, getLogger } from 'log4js' import { DataSource } from 'typeorm' - +import { Redis } from 'ioredis' import { GRADIDO_REALM, LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { AppDatabase } from 'database' import { context as serverContext } from './context' @@ -23,6 +23,7 @@ interface ServerDef { apollo: ApolloServer app: Express con: DataSource + db: AppDatabase } export const createServer = async ( @@ -104,5 +105,5 @@ export const createServer = async ( ) logger.debug('createServer...successful') - return { apollo, app, con: db.getDataSource() } + return { apollo, app, con: db.getDataSource(), db } } diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index c7f533931..687f5e331 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -35,7 +35,7 @@ export const testEnvironment = async (testLogger = getLogger('apollo'), testI18n const testClient = createTestClient(server.apollo) const mutate = testClient.mutate const query = testClient.query - return { mutate, query, con } + return { mutate, query, con, db: server.db } } export const resetEntity = async (entity: any) => { diff --git a/core/src/graphql/logic/settlePendingSenderTransaction.ts b/core/src/graphql/logic/settlePendingSenderTransaction.ts index c8ef678ac..2069892fb 100644 --- a/core/src/graphql/logic/settlePendingSenderTransaction.ts +++ b/core/src/graphql/logic/settlePendingSenderTransaction.ts @@ -14,13 +14,12 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '../../config/const' import { PendingTransactionState } from 'shared' // import { LogError } from '@/server/LogError' import { calculateSenderBalance } from '../../util/calculateSenderBalance' -import { TRANSACTIONS_LOCK, getLastTransaction } from 'database' +// import { TRANSACTIONS_LOCK, getLastTransaction } from 'database' +import { getLastTransaction } from 'database' import { getLogger } from 'log4js' -import { Redis } from 'ioredis' import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() -const redisClient = new Redis() const logger = getLogger( `${LOG4JS_BASE_CATEGORY_NAME}.graphql.logic.settlePendingSenderTransaction`, ) @@ -33,7 +32,7 @@ export async function settlePendingSenderTransaction( // TODO: synchronisation with TRANSACTION_LOCK of federation-modul necessary!!! // acquire lock // const releaseLock = await TRANSACTIONS_LOCK.acquire() - const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + const mutex = new Mutex(db.getRedisClient(), 'TRANSACTIONS_LOCK') await mutex.acquire() const queryRunner = db.getDataSource().createQueryRunner() diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts index 3096aaecd..13e33a8d3 100644 --- a/database/src/AppDatabase.ts +++ b/database/src/AppDatabase.ts @@ -5,12 +5,14 @@ import { getLogger } from 'log4js' import { latestDbVersion } from '.' import { CONFIG } from './config' import { LOG4JS_BASE_CATEGORY_NAME } from './config/const' +import Redis from 'ioredis' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.AppDatabase`) export class AppDatabase { private static instance: AppDatabase private dataSource: DBDataSource | undefined + private redisClient: Redis /** * The Singleton's constructor should always be private to prevent direct @@ -88,10 +90,24 @@ export class AppDatabase { } // check for correct database version await this.checkDBVersion() + + this.redisClient = new Redis(CONFIG.REDIS_URL) + console.log('Redis status=', this.redisClient.status) + logger.info('Redis status=', this.redisClient.status) } public async destroy(): Promise { await this.dataSource?.destroy() + if (this.redisClient) { + this.redisClient.quit() + } + } + + public getRedisClient(): Redis { + if (!this.redisClient) { + throw new Error('Redis client not initialized') + } + return this.redisClient } // ###################################### diff --git a/database/src/config/index.ts b/database/src/config/index.ts index fc6a4bb04..cac1f8e44 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -24,5 +24,6 @@ const database = { } const PRODUCTION = process.env.NODE_ENV === 'production' || false const nodeEnv = process.env.NODE_ENV || 'development' +const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379' -export const CONFIG = { ...database, NODE_ENV: nodeEnv, PRODUCTION, ...defaults } +export const CONFIG = { ...database, NODE_ENV: nodeEnv, PRODUCTION, REDIS_URL, ...defaults } From d49c8fdc4147ab3aa8c727aac0f25a794a270f81 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:14:32 +0100 Subject: [PATCH 127/226] fix release script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e022f9008..fb688a0e5 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "shared" ], "scripts": { - "release": "bumpp --no-commit --no-push -r", + "release": "bbump --no-commit --no-push -r", "version": "auto-changelog -p --commit-limit 0 && git add CHANGELOG.md", "installAll": "bun run install", "docker": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose -f docker-compose.yml up", From 2a5744bd97e0f3405d9bbfeb6b39dc9da833b02d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:14:43 +0100 Subject: [PATCH 128/226] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb688a0e5..c544288ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gradido", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido", "main": "index.js", "repository": "git@github.com:gradido/gradido.git", From d0eac55b0ad98a3fdee993718cd9e5e51d572856 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:15:15 +0100 Subject: [PATCH 129/226] update changelog --- CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa75018f..9d8683db1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,18 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [v2.7.0](https://github.com/gradido/gradido/compare/v2.7.0...v2.7.0) +#### [v2.7.1](https://github.com/gradido/gradido/compare/v2.7.0...v2.7.1) -- fixes [`414ff8a`](https://github.com/gradido/gradido/commit/414ff8ac5a7477109f80123ccca5c4c8ed4511b2) +- feat(frontend): new startpage images [`#3576`](https://github.com/gradido/gradido/pull/3576) +- feat(frontend): update login subtitle [`#3574`](https://github.com/gradido/gradido/pull/3574) +- feat(frontend): update copy symbol and change link order [`#3575`](https://github.com/gradido/gradido/pull/3575) +- fix(backend): correct seeding [`#3572`](https://github.com/gradido/gradido/pull/3572) +- feat(dlt): dlt-connector takes care of gradido node [`#3568`](https://github.com/gradido/gradido/pull/3568) +- refactor(dlt): upgrade dlt for using gradido blockchain lib and hiero [`#3551`](https://github.com/gradido/gradido/pull/3551) +- chore(release): v2.7.0 [`#3557`](https://github.com/gradido/gradido/pull/3557) +- feat(federation): use own table for handshake state [`#3555`](https://github.com/gradido/gradido/pull/3555) +- fix(workflow): use bun instead of yarn [`#3550`](https://github.com/gradido/gradido/pull/3550) +- feat(workflow): adjust for new bun version [`#3554`](https://github.com/gradido/gradido/pull/3554) #### [v2.7.0](https://github.com/gradido/gradido/compare/2.6.1...v2.7.0) From 44720f25b4710050d2a229951afd0818a3c2aa98 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:22:39 +0100 Subject: [PATCH 130/226] chore: release v2.7.1 --- admin/package.json | 2 +- backend/package.json | 2 +- config-schema/package.json | 2 +- core/package.json | 2 +- database/package.json | 2 +- dht-node/package.json | 2 +- federation/package.json | 2 +- frontend/package.json | 2 +- package.json | 4 ++-- shared/package.json | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/admin/package.json b/admin/package.json index 672da9425..463162667 100644 --- a/admin/package.json +++ b/admin/package.json @@ -3,7 +3,7 @@ "description": "Administration Interface for Gradido", "main": "index.js", "author": "Gradido Academy - https://www.gradido.net", - "version": "2.7.0", + "version": "2.7.1", "license": "Apache-2.0", "scripts": { "dev": "vite", diff --git a/backend/package.json b/backend/package.json index 5921bca92..d758c5518 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "backend", - "version": "2.7.0", + "version": "2.7.1", "private": false, "description": "Gradido unified backend providing an API-Service for Gradido Transactions", "repository": "https://github.com/gradido/gradido/backend", diff --git a/config-schema/package.json b/config-schema/package.json index e5fd4544b..0b843ce3c 100644 --- a/config-schema/package.json +++ b/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "config-schema", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido Config for validate config", "main": "./build/index.js", "types": "./src/index.ts", diff --git a/core/package.json b/core/package.json index 3771e3a8e..3e444d5d5 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "core", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido Core Code, High-Level Shared Code, with dependencies on other modules", "main": "./build/index.js", "types": "./src/index.ts", diff --git a/database/package.json b/database/package.json index 84504372c..73cfa260b 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "database", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido Database Tool to execute database migrations", "main": "./build/index.js", "types": "./src/index.ts", diff --git a/dht-node/package.json b/dht-node/package.json index a4c578c12..cb29f28f5 100644 --- a/dht-node/package.json +++ b/dht-node/package.json @@ -1,6 +1,6 @@ { "name": "dht-node", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido dht-node module", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/", diff --git a/federation/package.json b/federation/package.json index 7908ddf29..20176e3f9 100644 --- a/federation/package.json +++ b/federation/package.json @@ -1,6 +1,6 @@ { "name": "federation", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido federation module providing Gradido-Hub-Federation and versioned API for inter community communication", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/federation", diff --git a/frontend/package.json b/frontend/package.json index f8826b0b1..ade408c16 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "2.7.0", + "version": "2.7.1", "private": true, "scripts": { "dev": "concurrently \"yarn watch-scss\" \"vite\"", diff --git a/package.json b/package.json index c544288ee..0c9be0feb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "shared" ], "scripts": { - "release": "bbump --no-commit --no-push -r", + "release": "bumpp --no-commit --no-push -r", "version": "auto-changelog -p --commit-limit 0 && git add CHANGELOG.md", "installAll": "bun run install", "docker": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose -f docker-compose.yml up", @@ -39,7 +39,7 @@ "devDependencies": { "@biomejs/biome": "2.0.0", "@types/minimatch": "6.0.0", - "bbump": "^1.0.2" + "bumpp": "^10.3.1" }, "engines": { "node": ">=18" diff --git a/shared/package.json b/shared/package.json index 73e4e6832..4131cd774 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "shared", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido Shared Code, Low-Level Shared Code, without dependencies on other modules", "main": "./build/index.js", "types": "./src/index.ts", From 7c3a5a4cf1982740ee9a9c4c26b4648b0b034b30 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:23:01 +0100 Subject: [PATCH 131/226] fix wrong bump tool --- bun.lock | 109 +++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/bun.lock b/bun.lock index db5bdb51d..b3de8b9d2 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "name": "gradido", "dependencies": { "auto-changelog": "^2.4.0", + "bumpp": "^10.3.1", "cross-env": "^7.0.3", "jose": "^4.14.4", "turbo": "^2.5.0", @@ -1494,7 +1495,7 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], + "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -1550,6 +1551,8 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "args-tokenizer": ["args-tokenizer@0.3.0", "", {}, "sha512-xXAd7G2Mll5W8uo37GETpQ2VrE84M181Z7ugHFGQnJZ50M2mbOv0osSZ9VsSgPfJQ+LVG0prSi0th+ELMsno7Q=="], + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], "array-differ": ["array-differ@3.0.0", "", {}, "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg=="], @@ -1688,6 +1691,8 @@ "builtins": ["builtins@5.1.0", "", { "dependencies": { "semver": "^7.0.0" } }, "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg=="], + "bumpp": ["bumpp@10.3.1", "", { "dependencies": { "ansis": "^4.2.0", "args-tokenizer": "^0.3.0", "c12": "^3.3.0", "cac": "^6.7.14", "escalade": "^3.2.0", "jsonc-parser": "^3.3.1", "package-manager-detector": "^1.3.0", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.15", "yaml": "^2.8.1" }, "bin": { "bumpp": "bin/bumpp.mjs" } }, "sha512-cOKPRFCWvHcYPJQAHN6V7Jp/wAfnyqQRXQ+2fgWIL6Gao20rpu7xQ1cGGo1APOfmbQmmHngEPg9Fy7nJ3giRkQ=="], + "busboy": ["busboy@0.3.1", "", { "dependencies": { "dicer": "0.3.0" } }, "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -1782,7 +1787,7 @@ "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], - "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], @@ -1800,7 +1805,7 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], @@ -2846,7 +2851,7 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -2886,7 +2891,7 @@ "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], + "package-manager-detector": ["package-manager-detector@1.5.0", "", {}, "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw=="], "param-case": ["param-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="], @@ -2932,7 +2937,7 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], @@ -2942,7 +2947,7 @@ "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], - "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], "portal-vue": ["portal-vue@3.0.0", "", { "peerDependencies": { "vue": "^3.0.4" }, "optionalPeers": ["vue"] }, "sha512-9eprMxNURLx6ijbcgkWjYNcTWJYu/H8QF8nyAeBzOmk9lKCea01BW1hYBeLkgz+AestmPOvznAEOFmNuO4Adjw=="], @@ -3346,7 +3351,7 @@ "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -3638,7 +3643,7 @@ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], "yaml-eslint-parser": ["yaml-eslint-parser@0.5.0", "", { "dependencies": { "eslint-visitor-keys": "^3.0.0", "lodash": "^4.17.21", "yaml": "^1.10.2" } }, "sha512-nJeyLA3YHAzhBTZbRAbu3W6xrSCucyxExmA+ZDtEdUFpGllxAZpto2Zxo2IG0r0eiuEiBM4e+wiAdxTziTq94g=="], @@ -3662,6 +3667,10 @@ "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@antfu/install-pkg/package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], + + "@antfu/install-pkg/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "@apollo/protobufjs/@types/node": ["@types/node@10.17.60", "", {}, "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="], "@apollographql/graphql-upload-8-fork/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], @@ -3674,8 +3683,6 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], @@ -3760,6 +3767,8 @@ "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "@jest/transform/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], @@ -3768,22 +3777,18 @@ "@keyv/bigmap/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + "@morev/utils/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "@nuxt/kit/consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "@nuxt/kit/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "@nuxt/kit/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "@nuxt/kit/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - "@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "@selderee/plugin-htmlparser2/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], "@swc/cli/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], @@ -3870,6 +3875,8 @@ "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "apollo-boost/ts-invariant": ["ts-invariant@0.4.4", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA=="], "apollo-boost/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -3926,16 +3933,10 @@ "brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "c12/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "c12/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "cacheable/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -4104,6 +4105,8 @@ "jest-util/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], + "jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "jest-watcher/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], "jest-worker/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], @@ -4118,6 +4121,8 @@ "juice/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="], + "local-pkg/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "mailparser/html-to-text": ["html-to-text@9.0.5", "", { "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", "dom-serializer": "^2.0.0", "htmlparser2": "^8.0.2", "selderee": "^0.11.0" } }, "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg=="], @@ -4126,8 +4131,12 @@ "mailparser/nodemailer": ["nodemailer@7.0.9", "", {}, "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "multimatch/@types/minimatch": ["@types/minimatch@3.0.5", "", {}, "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="], "multimatch/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], @@ -4156,10 +4165,6 @@ "nypm/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "nypm/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - - "nypm/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], - "openai/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4252,8 +4257,6 @@ "test-exclude/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "ts-jest/jest": ["jest@27.5.1", "", { "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", "jest-cli": "^27.5.1" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"], "bin": { "jest": "bin/jest.js" } }, "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ=="], @@ -4262,6 +4265,8 @@ "type-graphql/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], + "typeorm/ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], + "typeorm/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], "typeorm/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -4282,20 +4287,16 @@ "unimport/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "unimport/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "unimport/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - "unimport/unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], "unplugin-utils/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "unplugin-utils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "unplugin-vue-components/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "unplugin-vue-components/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], @@ -4310,6 +4311,8 @@ "vite-plugin-html/pathe": ["pathe@0.2.0", "", {}, "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw=="], + "vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "vue/@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], "vue/@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], @@ -4334,6 +4337,8 @@ "xss/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "yaml-eslint-parser/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + "@apollographql/graphql-upload-8-fork/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], "@apollographql/graphql-upload-8-fork/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], @@ -4346,14 +4351,6 @@ "@hyperswarm/secret-stream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], - "@iconify/utils/@antfu/install-pkg/package-manager-detector": ["package-manager-detector@1.5.0", "", {}, "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw=="], - - "@iconify/utils/@antfu/install-pkg/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], - - "@iconify/utils/local-pkg/pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], - - "@intlify/bundle-utils/yaml-eslint-parser/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], - "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base": ["@intlify/core-base@10.0.8", "", { "dependencies": { "@intlify/message-compiler": "10.0.8", "@intlify/shared": "10.0.8" } }, "sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], @@ -4374,8 +4371,6 @@ "@jest/transform/write-file-atomic/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "@nuxt/kit/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "@swc/cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -4482,14 +4477,22 @@ "jest-worker/jest-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + "jest-worker/jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "js-beautify/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "jsdom/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "local-pkg/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "local-pkg/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "mailparser/html-to-text/@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], "mailparser/html-to-text/selderee": ["selderee@0.11.0", "", { "dependencies": { "parseley": "^0.12.0" } }, "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA=="], + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -4500,8 +4503,6 @@ "noise-curve-ed/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], - "nypm/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "run-applescript/execa/cross-spawn": ["cross-spawn@6.0.6", "", { "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw=="], @@ -4538,16 +4539,14 @@ "typeorm/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "unctx/unplugin/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "unimport/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - "unplugin-vue-components/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "unplugin-vue-components/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "unplugin-vue-components/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "vite-plugin-html/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], @@ -4616,10 +4615,6 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "@iconify/utils/local-pkg/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - - "@iconify/utils/local-pkg/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base/@intlify/message-compiler": ["@intlify/message-compiler@10.0.8", "", { "dependencies": { "@intlify/shared": "10.0.8", "source-map-js": "^1.0.2" } }, "sha512-DV+sYXIkHVd5yVb2mL7br/NEUwzUoLBsMkV3H0InefWgmYa34NLZUvMCGi5oWX+Hqr2Y2qUxnVrnOWF4aBlgWg=="], "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], @@ -4666,6 +4661,8 @@ "mailparser/html-to-text/selderee/parseley": ["parseley@0.12.1", "", { "dependencies": { "leac": "^0.6.0", "peberminta": "^0.9.0" } }, "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw=="], + "nodemon/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "run-applescript/execa/cross-spawn/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="], @@ -4682,6 +4679,8 @@ "typeorm/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "unplugin-vue-components/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "unplugin-vue-components/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "vue-apollo/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], From 17aaaa1c329721a1fcbbdade6143c20d0889227d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 21 Nov 2025 16:24:54 +0100 Subject: [PATCH 132/226] update bun.lock file --- bun.lock | 73 +++++++++----------------------------------------------- 1 file changed, 11 insertions(+), 62 deletions(-) diff --git a/bun.lock b/bun.lock index b3de8b9d2..7537ba4fb 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "name": "gradido", "dependencies": { "auto-changelog": "^2.4.0", - "bumpp": "^10.3.1", "cross-env": "^7.0.3", "jose": "^4.14.4", "turbo": "^2.5.0", @@ -14,12 +13,12 @@ "devDependencies": { "@biomejs/biome": "2.0.0", "@types/minimatch": "6.0.0", - "bbump": "^1.0.2", + "bumpp": "^10.3.1", }, }, "admin": { "name": "admin", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "@iconify/json": "^2.2.228", "@popperjs/core": "^2.11.8", @@ -89,7 +88,7 @@ }, "backend": { "name": "backend", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "cross-env": "^7.0.3", "email-templates": "^10.0.1", @@ -167,7 +166,7 @@ }, "config-schema": { "name": "config-schema", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "esbuild": "^0.25.2", "joi": "17.13.3", @@ -185,7 +184,7 @@ }, "core": { "name": "core", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "database": "*", "esbuild": "^0.25.2", @@ -214,7 +213,7 @@ }, "database": { "name": "database", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "@types/uuid": "^8.3.4", "cross-env": "^7.0.3", @@ -256,7 +255,7 @@ }, "dht-node": { "name": "dht-node", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "cross-env": "^7.0.3", "dht-rpc": "6.18.1", @@ -293,7 +292,7 @@ }, "federation": { "name": "federation", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "cross-env": "^7.0.3", "sodium-native": "^3.4.1", @@ -349,7 +348,7 @@ }, "frontend": { "name": "frontend", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "@morev/vue-transitions": "^3.0.2", "@types/leaflet": "^1.9.12", @@ -445,7 +444,7 @@ }, "shared": { "name": "shared", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "decimal.js-light": "^2.5.1", "esbuild": "^0.25.2", @@ -761,10 +760,6 @@ "@iconify/utils": ["@iconify/utils@2.3.0", "", { "dependencies": { "@antfu/install-pkg": "^1.0.0", "@antfu/utils": "^8.1.0", "@iconify/types": "^2.0.0", "debug": "^4.4.0", "globals": "^15.14.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "mlly": "^1.7.4" } }, "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA=="], - "@inquirer/external-editor": ["@inquirer/external-editor@1.0.2", "", { "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ=="], - - "@inquirer/figures": ["@inquirer/figures@1.0.14", "", {}, "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ=="], - "@intlify/bundle-utils": ["@intlify/bundle-utils@10.0.1", "", { "dependencies": { "@intlify/message-compiler": "^11.1.2", "@intlify/shared": "^11.1.2", "acorn": "^8.8.2", "escodegen": "^2.1.0", "estree-walker": "^2.0.2", "jsonc-eslint-parser": "^2.3.0", "mlly": "^1.2.0", "source-map-js": "^1.0.1", "yaml-eslint-parser": "^1.2.2" } }, "sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ=="], "@intlify/core-base": ["@intlify/core-base@9.13.1", "", { "dependencies": { "@intlify/message-compiler": "9.13.1", "@intlify/shared": "9.13.1" } }, "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w=="], @@ -1639,8 +1634,6 @@ "baseline-browser-mapping": ["baseline-browser-mapping@2.8.18", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w=="], - "bbump": ["bbump@1.0.2", "", { "dependencies": { "inquirer": "^9.0.0" }, "bin": { "bbump": "index.js" } }, "sha512-JGwlqjBF9cvPCjONPlb8R7YH4Uum8E06MJchUxpbjr2Ft7v/hjq+mM7zq93anI0Ww7sg9WAQulzCVDGUnd9YdQ=="], - "bignumber.js": ["bignumber.js@9.0.0", "", {}, "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="], "bin-version": ["bin-version@6.0.0", "", { "dependencies": { "execa": "^5.0.0", "find-versions": "^5.0.0" } }, "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw=="], @@ -1651,8 +1644,6 @@ "birpc": ["birpc@2.6.1", "", {}, "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ=="], - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], - "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], @@ -1729,8 +1720,6 @@ "character-parser": ["character-parser@2.2.0", "", { "dependencies": { "is-regex": "^1.0.3" } }, "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw=="], - "chardet": ["chardet@2.1.0", "", {}, "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="], - "check-error": ["check-error@2.1.1", "", {}, "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="], "cheerio": ["cheerio@1.0.0-rc.10", "", { "dependencies": { "cheerio-select": "^1.5.0", "dom-serializer": "^1.3.2", "domhandler": "^4.2.0", "htmlparser2": "^6.1.0", "parse5": "^6.0.1", "parse5-htmlparser2-tree-adapter": "^6.0.1", "tslib": "^2.2.0" } }, "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw=="], @@ -1751,18 +1740,10 @@ "clean-css": ["clean-css@5.3.3", "", { "dependencies": { "source-map": "~0.6.0" } }, "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg=="], - "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], - - "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], - - "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="], - "clipboard-polyfill": ["clipboard-polyfill@4.1.1", "", {}, "sha512-nbvNLrcX0zviek5QHLFRAaLrx8y/s8+RF2stH43tuS+kP5XlHMrcD0UGBWq43Hwp6WuuK7KefRMP56S45ibZkA=="], "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], - "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], "collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="], @@ -2369,8 +2350,6 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "inquirer": ["inquirer@9.3.8", "", { "dependencies": { "@inquirer/external-editor": "^1.0.2", "@inquirer/figures": "^1.0.3", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "1.0.0", "ora": "^5.4.1", "run-async": "^3.0.0", "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" } }, "sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w=="], - "inspect-with-kind": ["inspect-with-kind@1.0.5", "", { "dependencies": { "kind-of": "^6.0.2" } }, "sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g=="], "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], @@ -2415,8 +2394,6 @@ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], - "is-language-code": ["is-language-code@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.14.0" } }, "sha512-zJdQ3QTeLye+iphMeK3wks+vXSRFKh68/Pnlw7aOfApFSEIOhYa8P9vwwa6QrImNNBMJTiL1PpYF0f4BxDuEgA=="], "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], @@ -2455,8 +2432,6 @@ "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], - "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], - "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], @@ -2673,8 +2648,6 @@ "lodash.truncate": ["lodash.truncate@4.4.2", "", {}, "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="], - "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], - "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], "loglevel": ["loglevel@1.9.2", "", {}, "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg=="], @@ -2765,8 +2738,6 @@ "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], - "mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], - "mysql": ["mysql@2.18.1", "", { "dependencies": { "bignumber.js": "9.0.0", "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" } }, "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig=="], "mysql2": ["mysql2@2.3.3", "", { "dependencies": { "denque": "^2.0.1", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^4.0.0", "lru-cache": "^6.0.0", "named-placeholders": "^1.1.2", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA=="], @@ -2867,8 +2838,6 @@ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], "oxc-resolver": ["oxc-resolver@11.11.0", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.11.0", "@oxc-resolver/binding-android-arm64": "11.11.0", "@oxc-resolver/binding-darwin-arm64": "11.11.0", "@oxc-resolver/binding-darwin-x64": "11.11.0", "@oxc-resolver/binding-freebsd-x64": "11.11.0", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.11.0", "@oxc-resolver/binding-linux-arm-musleabihf": "11.11.0", "@oxc-resolver/binding-linux-arm64-gnu": "11.11.0", "@oxc-resolver/binding-linux-arm64-musl": "11.11.0", "@oxc-resolver/binding-linux-ppc64-gnu": "11.11.0", "@oxc-resolver/binding-linux-riscv64-gnu": "11.11.0", "@oxc-resolver/binding-linux-riscv64-musl": "11.11.0", "@oxc-resolver/binding-linux-s390x-gnu": "11.11.0", "@oxc-resolver/binding-linux-x64-gnu": "11.11.0", "@oxc-resolver/binding-linux-x64-musl": "11.11.0", "@oxc-resolver/binding-wasm32-wasi": "11.11.0", "@oxc-resolver/binding-win32-arm64-msvc": "11.11.0", "@oxc-resolver/binding-win32-ia32-msvc": "11.11.0", "@oxc-resolver/binding-win32-x64-msvc": "11.11.0" } }, "sha512-vVeBJf77zBeqOA/LBCTO/pr0/ETHGSleCRsI5Kmsf2OsfB5opzhhZptt6VxkqjKWZH+eF1se88fYDG5DGRLjkg=="], @@ -3103,8 +3072,6 @@ "responselike": ["responselike@3.0.0", "", { "dependencies": { "lowercase-keys": "^3.0.0" } }, "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg=="], - "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], - "ret": ["ret@0.1.15", "", {}, "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="], "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], @@ -3121,8 +3088,6 @@ "run-applescript": ["run-applescript@3.2.0", "", { "dependencies": { "execa": "^0.10.0" } }, "sha512-Ep0RsvAjnRcBX1p5vogbaBdAGu/8j/ewpvGqnQYunnLd9SM0vWcPJewPKNnWFggf0hF0pwIgwV5XK7qQ7UZ8Qg=="], - "run-async": ["run-async@3.0.0", "", {}, "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q=="], - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], @@ -3575,8 +3540,6 @@ "watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="], - "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], - "web-resource-inliner": ["web-resource-inliner@6.0.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", "htmlparser2": "^5.0.0", "mime": "^2.4.6", "node-fetch": "^2.6.0", "valid-data-url": "^3.0.0" } }, "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A=="], "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], @@ -3619,7 +3582,7 @@ "workerpool": ["workerpool@9.3.4", "", {}, "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg=="], - "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -3717,8 +3680,6 @@ "@iconify/utils/local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], - "@inquirer/external-editor/iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], - "@intlify/bundle-utils/@intlify/message-compiler": ["@intlify/message-compiler@11.1.12", "", { "dependencies": { "@intlify/shared": "11.1.12", "source-map-js": "^1.0.2" } }, "sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ=="], "@intlify/bundle-utils/@intlify/shared": ["@intlify/shared@11.1.12", "", {}, "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A=="], @@ -3923,10 +3884,6 @@ "backend/regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="], - "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - - "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -3955,8 +3912,6 @@ "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "concurrently/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "css-select/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], @@ -4185,8 +4140,6 @@ "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], - "run-applescript/execa": ["execa@0.10.0", "", { "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw=="], "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], @@ -4323,8 +4276,6 @@ "vue-apollo/throttle-debounce": ["throttle-debounce@2.3.0", "", {}, "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="], - "wcwidth/defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], - "web-resource-inliner/htmlparser2": ["htmlparser2@5.0.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", "domutils": "^2.4.2", "entities": "^2.0.0" } }, "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ=="], "web-resource-inliner/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], @@ -4639,8 +4590,6 @@ "html-to-text/htmlparser2/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], - "jest-cli/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "jest-environment-jsdom/jsdom/cssstyle/cssom": ["cssom@0.3.8", "", {}, "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="], "jest-environment-jsdom/jsdom/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], From 54c7f70976448fc16fd33878f17d1e642e7262b0 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 22 Nov 2025 12:40:05 +0100 Subject: [PATCH 133/226] change import to type, import actually entity later, speedup database test with bun --- bun.lock | 41 +++++++++--- database/bunfig.toml | 2 + database/package.json | 16 ++--- database/src/entity/Community.ts | 18 +++--- database/src/entity/Contribution.ts | 24 +++---- database/src/entity/ContributionMessage.ts | 16 ++--- database/src/entity/DltTransaction.ts | 24 +++---- database/src/entity/Event.ts | 44 ++++++------- database/src/entity/TransactionLink.ts | 24 +++---- database/src/entity/User.ts | 64 +++++++++---------- .../entity/transformer/GeometryTransformer.ts | 2 +- database/src/queries/communities.test.ts | 12 ++-- .../src/queries/communityHandshakes.test.ts | 1 - .../src/queries/pendingTransactions.test.ts | 1 - database/src/queries/user.test.ts | 3 +- database/vitest.config.js | 7 -- 16 files changed, 158 insertions(+), 141 deletions(-) create mode 100644 database/bunfig.toml delete mode 100644 database/vitest.config.js diff --git a/bun.lock b/bun.lock index 7537ba4fb..0ac634ee8 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "gradido", @@ -213,7 +214,7 @@ }, "database": { "name": "database", - "version": "2.7.1", + "version": "2.7.0", "dependencies": { "@types/uuid": "^8.3.4", "cross-env": "^7.0.3", @@ -221,9 +222,10 @@ "dotenv": "^10.0.0", "esbuild": "^0.25.2", "geojson": "^0.5.0", + "ioredis": "^5.8.2", "log4js": "^6.9.1", "mysql": "^2.18.1", - "mysql2": "^2.3.0", + "mysql2": "^3.15.3", "reflect-metadata": "^0.1.13", "shared": "*", "source-map-support": "^0.5.21", @@ -250,7 +252,6 @@ "ts-jest": "27.0.5", "ts-node": "^10.9.2", "typescript": "^4.9.5", - "vitest": "^2.0.5", }, }, "dht-node": { @@ -774,6 +775,8 @@ "@intlify/vue-i18n-extensions": ["@intlify/vue-i18n-extensions@8.0.0", "", { "dependencies": { "@babel/parser": "^7.24.6", "@intlify/shared": "^10.0.0", "@vue/compiler-dom": "^3.2.45", "vue-i18n": "^10.0.0" }, "peerDependencies": { "vue": "^3.0.0" }, "optionalPeers": ["vue"] }, "sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ=="], + "@ioredis/commands": ["@ioredis/commands@1.4.0", "", {}, "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ=="], + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], @@ -1594,6 +1597,8 @@ "await-semaphore": ["await-semaphore@0.1.3", "", {}, "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "axios": ["axios@0.21.4", "", { "dependencies": { "follow-redirects": "^1.14.0" } }, "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="], "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], @@ -1744,6 +1749,8 @@ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], "collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="], @@ -2322,7 +2329,7 @@ "i18n-locales": ["i18n-locales@0.0.5", "", { "dependencies": { "@ladjs/country-language": "^0.2.1" } }, "sha512-Kve1AHy6rqyfJHPy8MIvaKBKhHhHPXV+a/TgMkjp3UBhO3gfWR40ZQn8Xy7LI6g3FhmbvkFtv+GCZy6yvuyeHQ=="], - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], "identity-obj-proxy": ["identity-obj-proxy@3.0.0", "", { "dependencies": { "harmony-reflect": "^1.4.6" } }, "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA=="], @@ -2354,6 +2361,8 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "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" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], @@ -2638,8 +2647,12 @@ "lodash.clonedeep": ["lodash.clonedeep@4.5.0", "", {}, "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="], + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + "lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="], + "lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="], + "lodash.memoize": ["lodash.memoize@4.1.2", "", {}, "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="], "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], @@ -2652,7 +2665,7 @@ "loglevel": ["loglevel@1.9.2", "", {}, "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg=="], - "long": ["long@4.0.0", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -2664,6 +2677,8 @@ "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], + "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], @@ -2740,7 +2755,7 @@ "mysql": ["mysql@2.18.1", "", { "dependencies": { "bignumber.js": "9.0.0", "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" } }, "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig=="], - "mysql2": ["mysql2@2.3.3", "", { "dependencies": { "denque": "^2.0.1", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^4.0.0", "lru-cache": "^6.0.0", "named-placeholders": "^1.1.2", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA=="], + "mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="], "named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], @@ -3036,6 +3051,10 @@ "record-cache": ["record-cache@1.2.0", "", { "dependencies": { "b4a": "^1.3.1" } }, "sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw=="], + "redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="], + + "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], + "reflect-metadata": ["reflect-metadata@0.1.14", "", {}, "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -3202,6 +3221,8 @@ "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], @@ -3636,6 +3657,8 @@ "@apollo/protobufjs/@types/node": ["@types/node@10.17.60", "", {}, "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="], + "@apollo/protobufjs/long": ["long@4.0.0", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="], + "@apollographql/graphql-upload-8-fork/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], "@asamuzakjp/css-color/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4076,14 +4099,14 @@ "juice/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="], + "libmime/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "local-pkg/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "mailparser/html-to-text": ["html-to-text@9.0.5", "", { "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", "dom-serializer": "^2.0.0", "htmlparser2": "^8.0.2", "selderee": "^0.11.0" } }, "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg=="], - "mailparser/iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], - "mailparser/nodemailer": ["nodemailer@7.0.9", "", {}, "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -4282,6 +4305,8 @@ "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], + "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "wkx/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], diff --git a/database/bunfig.toml b/database/bunfig.toml new file mode 100644 index 000000000..6e74bf7ca --- /dev/null +++ b/database/bunfig.toml @@ -0,0 +1,2 @@ +[test] +preload = ["../config-schema/test/testSetup.bun.ts"] diff --git a/database/package.json b/database/package.json index 73cfa260b..ed7aa56e4 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "database", - "version": "2.7.1", + "version": "2.7.0", "description": "Gradido Database Tool to execute database migrations", "main": "./build/index.js", "types": "./src/index.ts", @@ -15,13 +15,13 @@ "license": "Apache-2.0", "private": true, "scripts": { - "build": "tsx ./esbuild.config.ts", + "build": "bun ./esbuild.config.ts", "typecheck": "tsc --noEmit", "lint": "biome check --error-on-warnings .", "lint:fix": "biome check --error-on-warnings . --write", "clearDB": "cross-env TZ=UTC tsx migration/index.ts clear", - "test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test vitest --reporter verbose --no-file-parallelism run", - "test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test node --inspect-brk node_modules/.bin/jest --bail --runInBand --forceExit --detectOpenHandles", + "test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test bun test", + "test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test bun test --inspect-brk", "up": "cross-env TZ=UTC tsx migration/index.ts up", "down": "cross-env TZ=UTC tsx migration/index.ts down", "reset": "cross-env TZ=UTC tsx migration/index.ts reset", @@ -39,16 +39,12 @@ "@swc/helpers": "^0.5.17", "@types/faker": "^5.5.9", "@types/geojson": "^7946.0.13", - "@types/jest": "27.0.2", "@types/mysql": "^2.15.27", "@types/node": "^18.7.14", "await-semaphore": "^0.1.3", "crypto-random-bigint": "^2.1.1", - "jest": "27.2.4", - "ts-jest": "27.0.5", "ts-node": "^10.9.2", - "typescript": "^4.9.5", - "vitest": "^2.0.5" + "typescript": "^4.9.5" }, "dependencies": { "@types/uuid": "^8.3.4", @@ -59,7 +55,7 @@ "geojson": "^0.5.0", "log4js": "^6.9.1", "mysql": "^2.18.1", - "mysql2": "^2.3.0", + "mysql2": "^3.15.3", "reflect-metadata": "^0.1.13", "shared": "*", "source-map-support": "^0.5.21", diff --git a/database/src/entity/Community.ts b/database/src/entity/Community.ts index f6597306a..e21226d44 100644 --- a/database/src/entity/Community.ts +++ b/database/src/entity/Community.ts @@ -3,14 +3,14 @@ import { Column, CreateDateColumn, Entity, - Geometry, + type Geometry, JoinColumn, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm' -import { FederatedCommunity } from './FederatedCommunity' -import { User } from './User' +import { type FederatedCommunity as FederatedCommunityType } from './FederatedCommunity' +import { type User as UserType } from './User' import { GeometryTransformer } from './transformer/GeometryTransformer' @Entity('communities') @@ -95,16 +95,16 @@ export class Community extends BaseEntity { updatedAt: Date | null @OneToMany( - () => User, - (user) => user.community, + () => require('./User').User, + (user: UserType) => user.community, ) @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) - users: User[] + users: UserType[] @OneToMany( - () => FederatedCommunity, - (federatedCommunity) => federatedCommunity.community, + () => require('./FederatedCommunity').FederatedCommunity, + (federatedCommunity: FederatedCommunityType) => federatedCommunity.community, ) @JoinColumn({ name: 'public_key', referencedColumnName: 'publicKey' }) - federatedCommunities?: FederatedCommunity[] + federatedCommunities?: FederatedCommunityType[] } diff --git a/database/src/entity/Contribution.ts b/database/src/entity/Contribution.ts index 976385263..242eae06f 100644 --- a/database/src/entity/Contribution.ts +++ b/database/src/entity/Contribution.ts @@ -10,9 +10,9 @@ import { OneToOne, PrimaryGeneratedColumn, } from 'typeorm' -import { ContributionMessage } from './ContributionMessage' -import { Transaction } from './Transaction' -import { User } from './User' +import { type ContributionMessage as ContributionMessageType } from './ContributionMessage' +import { type Transaction as TransactionType } from './Transaction' +import { type User as UserType } from './User' import { DecimalTransformer } from './transformer/DecimalTransformer' @Entity('contributions') @@ -24,11 +24,11 @@ export class Contribution extends BaseEntity { userId: number @ManyToOne( - () => User, - (user) => user.contributions, + () => require('./User').User, + (user: UserType) => user.contributions, ) @JoinColumn({ name: 'user_id' }) - user: User + user: UserType @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' }) createdAt: Date @@ -103,16 +103,16 @@ export class Contribution extends BaseEntity { deletedBy: number @OneToMany( - () => ContributionMessage, - (message) => message.contribution, + () => require('./ContributionMessage').ContributionMessage, + (message: ContributionMessageType) => message.contribution, ) @JoinColumn({ name: 'contribution_id' }) - messages?: ContributionMessage[] + messages?: ContributionMessageType[] @OneToOne( - () => Transaction, - (transaction) => transaction.contribution, + () => require('./Transaction').Transaction, + (transaction: TransactionType) => transaction.contribution, ) @JoinColumn({ name: 'transaction_id' }) - transaction?: Transaction | null + transaction?: TransactionType | null } diff --git a/database/src/entity/ContributionMessage.ts b/database/src/entity/ContributionMessage.ts index 1b76243e8..b6fde3815 100644 --- a/database/src/entity/ContributionMessage.ts +++ b/database/src/entity/ContributionMessage.ts @@ -10,8 +10,8 @@ import { PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm' -import { Contribution } from './Contribution' -import { User } from './User' +import { type Contribution as ContributionType } from './Contribution' +import { type User as UserType } from './User' @Entity('contribution_messages', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci', @@ -25,21 +25,21 @@ export class ContributionMessage extends BaseEntity { contributionId: number @ManyToOne( - () => Contribution, - (contribution) => contribution.messages, + () => require('./Contribution').Contribution, + (contribution: ContributionType) => contribution.messages, ) @JoinColumn({ name: 'contribution_id' }) - contribution: Contribution + contribution: ContributionType @Column({ name: 'user_id', type: 'bigint', unsigned: true, nullable: false }) userId: number @ManyToOne( - () => User, - (user) => user.messages, + () => require('./User').User, + (user: UserType) => user.messages, ) @JoinColumn({ name: 'user_id' }) - user: User + user: UserType @Column({ type: 'varchar', length: 2000, nullable: false, collation: 'utf8mb4_unicode_ci' }) message: string diff --git a/database/src/entity/DltTransaction.ts b/database/src/entity/DltTransaction.ts index 2df3fb92c..46cccd0f6 100644 --- a/database/src/entity/DltTransaction.ts +++ b/database/src/entity/DltTransaction.ts @@ -1,7 +1,7 @@ import { BaseEntity, Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm' -import { Transaction } from './Transaction' -import { TransactionLink } from './TransactionLink' -import { User } from './User' +import { type Transaction as TransactionType } from './Transaction' +import { type TransactionLink as TransactionLinkType } from './TransactionLink' +import { type User as UserType } from './User' @Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class DltTransaction extends BaseEntity { @@ -49,23 +49,23 @@ export class DltTransaction extends BaseEntity { error: string | null @OneToOne( - () => Transaction, - (transaction) => transaction.dltTransaction, + () => require('./Transaction').Transaction, + (transaction: TransactionType) => transaction.dltTransaction, ) @JoinColumn({ name: 'transaction_id' }) - transaction?: Transaction | null + transaction?: TransactionType | null @OneToOne( - () => User, - (user) => user.dltTransaction, + () => require('./User').User, + (user: UserType) => user.dltTransaction, ) @JoinColumn({ name: 'user_id' }) - user?: User | null + user?: UserType | null @OneToOne( - () => TransactionLink, - (transactionLink) => transactionLink.dltTransaction, + () => require('./TransactionLink').TransactionLink, + (transactionLink: TransactionLinkType) => transactionLink.dltTransaction, ) @JoinColumn({ name: 'transaction_link_id' }) - transactionLink?: TransactionLink | null + transactionLink?: TransactionLinkType | null } diff --git a/database/src/entity/Event.ts b/database/src/entity/Event.ts index 9d17ffdeb..4adbe6e51 100644 --- a/database/src/entity/Event.ts +++ b/database/src/entity/Event.ts @@ -8,12 +8,12 @@ import { ManyToOne, PrimaryGeneratedColumn, } from 'typeorm' -import { Contribution } from './Contribution' -import { ContributionLink } from './ContributionLink' -import { ContributionMessage } from './ContributionMessage' -import { Transaction } from './Transaction' -import { TransactionLink } from './TransactionLink' -import { User } from './User' +import { type Contribution as ContributionType } from './Contribution' +import { type ContributionLink as ContributionLinkType } from './ContributionLink' +import { type ContributionMessage as ContributionMessageType } from './ContributionMessage' +import { type Transaction as TransactionType } from './Transaction' +import { type TransactionLink as TransactionLinkType } from './TransactionLink' +import { type User as UserType } from './User' import { DecimalTransformer } from './transformer/DecimalTransformer' @Entity('events') @@ -36,37 +36,37 @@ export class Event extends BaseEntity { @Column({ name: 'affected_user_id', type: 'bigint', unsigned: true, nullable: false }) affectedUserId: number - @ManyToOne(() => User) + @ManyToOne(() => require('./User').User) @JoinColumn({ name: 'affected_user_id', referencedColumnName: 'id' }) - affectedUser: User + affectedUser: UserType @Column({ name: 'acting_user_id', type: 'bigint', unsigned: true, nullable: false }) actingUserId: number - @ManyToOne(() => User) + @ManyToOne(() => require('./User').User) @JoinColumn({ name: 'acting_user_id', referencedColumnName: 'id' }) - actingUser: User + actingUser: UserType @Column({ name: 'involved_user_id', type: 'bigint', unsigned: true, nullable: true }) involvedUserId: number | null - @ManyToOne(() => User) + @ManyToOne(() => require('./User').User) @JoinColumn({ name: 'involved_user_id', referencedColumnName: 'id' }) - involvedUser: User | null + involvedUser: UserType | null @Column({ name: 'involved_transaction_id', type: 'bigint', unsigned: true, nullable: true }) involvedTransactionId: number | null - @ManyToOne(() => Transaction) + @ManyToOne(() => require('./Transaction').Transaction) @JoinColumn({ name: 'involved_transaction_id', referencedColumnName: 'id' }) - involvedTransaction: Transaction | null + involvedTransaction: TransactionType | null @Column({ name: 'involved_contribution_id', type: 'bigint', unsigned: true, nullable: true }) involvedContributionId: number | null - @ManyToOne(() => Contribution) + @ManyToOne(() => require('./Contribution').Contribution) @JoinColumn({ name: 'involved_contribution_id', referencedColumnName: 'id' }) - involvedContribution: Contribution | null + involvedContribution: ContributionType | null @Column({ name: 'involved_contribution_message_id', @@ -76,23 +76,23 @@ export class Event extends BaseEntity { }) involvedContributionMessageId: number | null - @ManyToOne(() => ContributionMessage) + @ManyToOne(() => require('./ContributionMessage').ContributionMessage) @JoinColumn({ name: 'involved_contribution_message_id', referencedColumnName: 'id' }) - involvedContributionMessage: ContributionMessage | null + involvedContributionMessage: ContributionMessageType | null @Column({ name: 'involved_transaction_link_id', type: 'bigint', unsigned: true, nullable: true }) involvedTransactionLinkId: number | null - @ManyToOne(() => TransactionLink) + @ManyToOne(() => require('./TransactionLink').TransactionLink) @JoinColumn({ name: 'involved_transaction_link_id', referencedColumnName: 'id' }) - involvedTransactionLink: TransactionLink | null + involvedTransactionLink: TransactionLinkType | null @Column({ name: 'involved_contribution_link_id', type: 'bigint', unsigned: true, nullable: true }) involvedContributionLinkId: number | null - @ManyToOne(() => ContributionLink) + @ManyToOne(() => require('./ContributionLink').ContributionLink) @JoinColumn({ name: 'involved_contribution_link_id', referencedColumnName: 'id' }) - involvedContributionLink: ContributionLink | null + involvedContributionLink: ContributionLinkType | null @Column({ type: 'decimal', diff --git a/database/src/entity/TransactionLink.ts b/database/src/entity/TransactionLink.ts index 326573c16..7fe755a7a 100644 --- a/database/src/entity/TransactionLink.ts +++ b/database/src/entity/TransactionLink.ts @@ -9,10 +9,10 @@ import { OneToOne, PrimaryGeneratedColumn, } from 'typeorm' -import { DltTransaction } from './DltTransaction' -import { Transaction } from './Transaction' +import { type DltTransaction as DltTransactionType } from './DltTransaction' +import { type Transaction as TransactionType } from './Transaction' import { DecimalTransformer } from './transformer/DecimalTransformer' -import { User } from './User' +import { type User as UserType } from './User' @Entity('transaction_links') export class TransactionLink extends BaseEntity { @@ -72,23 +72,23 @@ export class TransactionLink extends BaseEntity { redeemedBy: number | null @OneToOne( - () => DltTransaction, - (dlt) => dlt.transactionLinkId, + () => require('./DltTransaction').DltTransaction, + (dlt: DltTransactionType) => dlt.transactionLinkId, ) @JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' }) - dltTransaction?: DltTransaction | null + dltTransaction?: DltTransactionType | null @OneToOne( - () => User, - (user) => user.transactionLink, + () => require('./User').User, + (user: UserType) => user.transactionLink, ) @JoinColumn({ name: 'userId' }) - user: User + user: UserType @OneToMany( - () => Transaction, - (transaction) => transaction.transactionLink, + () => require('./Transaction').Transaction, + (transaction: TransactionType) => transaction.transactionLink, ) @JoinColumn({ referencedColumnName: 'transaction_link_id' }) - transactions: Transaction[] + transactions: TransactionType[] } diff --git a/database/src/entity/User.ts b/database/src/entity/User.ts index 6a40e9858..20219e4f7 100644 --- a/database/src/entity/User.ts +++ b/database/src/entity/User.ts @@ -3,20 +3,20 @@ import { Column, DeleteDateColumn, Entity, - Geometry, + type Geometry, JoinColumn, ManyToOne, OneToMany, OneToOne, PrimaryGeneratedColumn, } from 'typeorm' -import { Community } from './Community' -import { Contribution } from './Contribution' -import { ContributionMessage } from './ContributionMessage' -import { DltTransaction } from './DltTransaction' -import { TransactionLink } from './TransactionLink' -import { UserContact } from './UserContact' -import { UserRole } from './UserRole' +import { type Community as CommunityType } from './Community' +import { type Contribution as ContributionType } from './Contribution' +import { type ContributionMessage as ContributionMessageType } from './ContributionMessage' +import { type DltTransaction as DltTransactionType } from './DltTransaction' +import { type TransactionLink as TransactionLinkType } from './TransactionLink' +import { type UserContact as UserContactType } from './UserContact' +import { type UserRole as UserRoleType } from './UserRole' import { GeometryTransformer } from './transformer/GeometryTransformer' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) @@ -46,11 +46,11 @@ export class User extends BaseEntity { communityUuid: string @ManyToOne( - () => Community, - (community) => community.users, + () => require('./Community').Community, + (community: CommunityType) => community.users, ) @JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' }) - community: Community | null + community: CommunityType | null @Column({ name: 'alias', @@ -63,11 +63,11 @@ export class User extends BaseEntity { alias: string @OneToOne( - () => UserContact, - (emailContact: UserContact) => emailContact.user, + () => require('./UserContact').UserContact, + (emailContact: UserContactType) => emailContact.user, ) @JoinColumn({ name: 'email_id' }) - emailContact: UserContact + emailContact: UserContactType @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) emailId: number | null @@ -138,11 +138,11 @@ export class User extends BaseEntity { hideAmountGDT: boolean @OneToMany( - () => UserRole, - (userRole) => userRole.user, + () => require('./UserRole').UserRole, + (userRole: UserRoleType) => userRole.user, ) @JoinColumn({ name: 'user_id' }) - userRoles: UserRole[] + userRoles: UserRoleType[] @Column({ name: 'referrer_id', type: 'bigint', unsigned: true, nullable: true, default: null }) referrerId?: number | null @@ -196,37 +196,37 @@ export class User extends BaseEntity { humhubAllowed: boolean @OneToMany( - () => Contribution, - (contribution) => contribution.user, + () => require('./Contribution').Contribution, + (contribution: ContributionType) => contribution.user, ) @JoinColumn({ name: 'user_id' }) - contributions?: Contribution[] + contributions?: ContributionType[] @OneToMany( - () => ContributionMessage, - (message) => message.user, + () => require('./ContributionMessage').ContributionMessage, + (message: ContributionMessageType) => message.user, ) @JoinColumn({ name: 'user_id' }) - messages?: ContributionMessage[] + messages?: ContributionMessageType[] @OneToMany( - () => UserContact, - (userContact: UserContact) => userContact.user, + () => require('./UserContact').UserContact, + (userContact: UserContactType) => userContact.user, ) @JoinColumn({ name: 'user_id' }) - userContacts?: UserContact[] + userContacts?: UserContactType[] @OneToOne( - () => DltTransaction, - (dlt) => dlt.userId, + () => require('./DltTransaction').DltTransaction, + (dlt: DltTransactionType) => dlt.userId, ) @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) - dltTransaction?: DltTransaction | null + dltTransaction?: DltTransactionType | null @OneToOne( - () => TransactionLink, - (transactionLink) => transactionLink.userId, + () => require('./TransactionLink').TransactionLink, + (transactionLink: TransactionLinkType) => transactionLink.userId, ) @JoinColumn({ name: 'id', referencedColumnName: 'userId' }) - transactionLink?: TransactionLink | null + transactionLink?: TransactionLinkType | null } diff --git a/database/src/entity/transformer/GeometryTransformer.ts b/database/src/entity/transformer/GeometryTransformer.ts index bc80d256b..b877f2c38 100644 --- a/database/src/entity/transformer/GeometryTransformer.ts +++ b/database/src/entity/transformer/GeometryTransformer.ts @@ -1,4 +1,4 @@ -import { Geometry } from 'geojson' +import { type Geometry } from 'geojson' import { ValueTransformer } from 'typeorm/decorator/options/ValueTransformer' import { Geometry as wkx_Geometry } from 'wkx' diff --git a/database/src/queries/communities.test.ts b/database/src/queries/communities.test.ts index b435c3649..1f5135994 100644 --- a/database/src/queries/communities.test.ts +++ b/database/src/queries/communities.test.ts @@ -1,7 +1,11 @@ import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from '..' import { AppDatabase } from '../AppDatabase' -import { getCommunityByPublicKeyOrFail, getHomeCommunity, getHomeCommunityWithFederatedCommunityOrFail, getReachableCommunities } from './communities' -import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest' +import { + getCommunityByPublicKeyOrFail, + getHomeCommunity, + getHomeCommunityWithFederatedCommunityOrFail, + getReachableCommunities +} from './communities' import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community' import { Ed25519PublicKey } from 'shared' @@ -50,12 +54,12 @@ describe('community.queries', () => { }) it('should throw if no home community exists', async () => { - expect(() => getHomeCommunityWithFederatedCommunityOrFail('1_0')).rejects.toThrow() + expect(getHomeCommunityWithFederatedCommunityOrFail('1_0')).rejects.toThrow() }) it('should throw if no federated community exists', async () => { await createCommunity(false) - expect(() => getHomeCommunityWithFederatedCommunityOrFail('1_0')).rejects.toThrow() + expect(getHomeCommunityWithFederatedCommunityOrFail('1_0')).rejects.toThrow() }) it('load community by public key returned from getHomeCommunityWithFederatedCommunityOrFail', async () => { diff --git a/database/src/queries/communityHandshakes.test.ts b/database/src/queries/communityHandshakes.test.ts index 372fb1293..09937cc66 100644 --- a/database/src/queries/communityHandshakes.test.ts +++ b/database/src/queries/communityHandshakes.test.ts @@ -6,7 +6,6 @@ import { findPendingCommunityHandshake, CommunityHandshakeStateType } from '..' -import { describe, expect, it, beforeEach, beforeAll, afterAll } from 'vitest' import { createCommunity, createVerifiedFederatedCommunity } from '../seeds/community' import { Ed25519PublicKey } from 'shared' import { randomBytes } from 'node:crypto' diff --git a/database/src/queries/pendingTransactions.test.ts b/database/src/queries/pendingTransactions.test.ts index c59c312e4..a4765dcee 100644 --- a/database/src/queries/pendingTransactions.test.ts +++ b/database/src/queries/pendingTransactions.test.ts @@ -13,7 +13,6 @@ import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' import { garrickOllivander } from '../seeds/users/garrick-ollivander' -import { describe, expect, it, beforeAll, afterAll } from 'vitest' import { createCommunity } from '../seeds/community' import { v4 as uuidv4 } from 'uuid' import Decimal from 'decimal.js-light' diff --git a/database/src/queries/user.test.ts b/database/src/queries/user.test.ts index b653a5349..6348c01d8 100644 --- a/database/src/queries/user.test.ts +++ b/database/src/queries/user.test.ts @@ -3,11 +3,10 @@ import { AppDatabase } from '../AppDatabase' import { aliasExists, findUserByIdentifier } from './user' import { userFactory } from '../seeds/factory/user' import { bibiBloxberg } from '../seeds/users/bibi-bloxberg' -import { describe, expect, it, beforeAll, afterAll, beforeEach, } from 'vitest' import { createCommunity } from '../seeds/community' import { peterLustig } from '../seeds/users/peter-lustig' import { bobBaumeister } from '../seeds/users/bob-baumeister' -import { getLogger, printLogs, clearLogs } from '../../../config-schema/test/testSetup.vitest' +import { getLogger, printLogs, clearLogs } from '../../../config-schema/test/testSetup.bun' import { LOG4JS_QUERIES_CATEGORY_NAME } from '.' const db = AppDatabase.getInstance() diff --git a/database/vitest.config.js b/database/vitest.config.js deleted file mode 100644 index b0e269a1a..000000000 --- a/database/vitest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - setupFiles: '../config-schema/test/testSetup.vitest.ts', - }, -}) \ No newline at end of file From fc7987460655e193c9f610124437c1cce9aacbe3 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 22 Nov 2025 12:41:20 +0100 Subject: [PATCH 134/226] fix wrong version --- bun.lock | 10 +--------- database/package.json | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/bun.lock b/bun.lock index 0ac634ee8..4b94f4bc7 100644 --- a/bun.lock +++ b/bun.lock @@ -214,7 +214,7 @@ }, "database": { "name": "database", - "version": "2.7.0", + "version": "2.7.1", "dependencies": { "@types/uuid": "^8.3.4", "cross-env": "^7.0.3", @@ -222,7 +222,6 @@ "dotenv": "^10.0.0", "esbuild": "^0.25.2", "geojson": "^0.5.0", - "ioredis": "^5.8.2", "log4js": "^6.9.1", "mysql": "^2.18.1", "mysql2": "^3.15.3", @@ -243,13 +242,10 @@ "@swc/helpers": "^0.5.17", "@types/faker": "^5.5.9", "@types/geojson": "^7946.0.13", - "@types/jest": "27.0.2", "@types/mysql": "^2.15.27", "@types/node": "^18.7.14", "await-semaphore": "^0.1.3", "crypto-random-bigint": "^2.1.1", - "jest": "27.2.4", - "ts-jest": "27.0.5", "ts-node": "^10.9.2", "typescript": "^4.9.5", }, @@ -3945,8 +3941,6 @@ "database/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], - "database/ts-jest": ["ts-jest@27.0.5", "", { "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^27.0.0", "json5": "2.x", "lodash": "4.x", "make-error": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, "optionalPeers": ["@babel/core", "@types/jest", "babel-jest"], "bin": { "ts-jest": "cli.js" } }, "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w=="], - "decompress-response/mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], "dht-node/@types/jest": ["@types/jest@27.5.1", "", { "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" } }, "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ=="], @@ -4383,8 +4377,6 @@ "css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], - "database/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - "dht-node/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], "dht-rpc/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], diff --git a/database/package.json b/database/package.json index ed7aa56e4..2adcd10af 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "database", - "version": "2.7.0", + "version": "2.7.1", "description": "Gradido Database Tool to execute database migrations", "main": "./build/index.js", "types": "./src/index.ts", From 5803c34d7b545a7fa52078763612b60a851be1fc Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 22 Nov 2025 12:43:23 +0100 Subject: [PATCH 135/226] remove not longer used module --- bun.lock | 60 ------------------------------------------ database/package.json | 4 --- database/tsconfig.json | 3 --- 3 files changed, 67 deletions(-) diff --git a/bun.lock b/bun.lock index 4b94f4bc7..0f2ac4c20 100644 --- a/bun.lock +++ b/bun.lock @@ -236,10 +236,6 @@ }, "devDependencies": { "@biomejs/biome": "2.0.0", - "@swc-node/register": "^1.10.10", - "@swc/cli": "^0.7.3", - "@swc/core": "^1.11.24", - "@swc/helpers": "^0.5.17", "@types/faker": "^5.5.9", "@types/geojson": "^7946.0.13", "@types/mysql": "^2.15.27", @@ -653,12 +649,6 @@ "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="], - "@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], - - "@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], - - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="], @@ -883,8 +873,6 @@ "@napi-rs/nice-win32-x64-msvc": ["@napi-rs/nice-win32-x64-msvc@1.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], @@ -895,44 +883,6 @@ "@one-ini/wasm": ["@one-ini/wasm@0.1.1", "", {}, "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="], - "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.11.0", "", { "os": "android", "cpu": "arm" }, "sha512-aN0UJg1xr0N1dADQ135z4p3bP9AYAUN1Ey2VvLMK6IwWYIJGWpKT+cr1l3AiyBeLK8QZyFDb4IDU8LHgjO9TDQ=="], - - "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.11.0", "", { "os": "android", "cpu": "arm64" }, "sha512-FckvvMclo8CSJqQjKpHueIIbKrg9L638NKWQTiJQaD8W9F61h8hTjF8+QFLlCHh6R9RcE5roVHdkkiBKHlB2Zw=="], - - "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.11.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7ZcpgaXSBnwRHM1YR8Vazq7mCTtGdYRvM7k46CscA+oipCVqmI4LbW2wLsc6HVjqX+SM/KPOfFGoGjEgmQPFTQ=="], - - "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.11.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Wsd1JWORokMmOKrR4t4jxpwYEWG11+AHWu9bdzjCO5EIyi0AuNpPIAEcEFCP9FNd0h8c+VUYbMRU/GooD2zOIg=="], - - "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.11.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YX+W10kHrMouu/+Y+rqJdCWO3dFBKM1DIils30PHsmXWp1v+ZZvhibaST2BP6zrWkWquZ8pMmsObD6N10lLgiA=="], - - "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.11.0", "", { "os": "linux", "cpu": "arm" }, "sha512-UAhlhVkW2ui98bClmEkDLKQz4XBSccxMahG7rMeX2RepS2QByAWxYFFThaNbHtBSB+B4Rc1hudkihq8grQkU3g=="], - - "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.11.0", "", { "os": "linux", "cpu": "arm" }, "sha512-5pEliabSEiimXz/YyPxzyBST82q8PbM6BoEMS8kOyaDbEBuzTr7pWU1U0F7ILGBFjJmHaj3N7IAhQgeXdpdySg=="], - - "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.11.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-CiyufPFIOJrW/HovAMGsH0AbV7BSCb0oE0KDtt7z1+e+qsDo7HRlTSnqE3JbNuhJRg3Cz/j7qEYzgGqco9SE4Q=="], - - "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.11.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-w07MfGtDLZV0rISdXl2cGASxD/sRrrR93Qd4q27O2Hsky4MGbLw94trbzhmAkc7OKoJI0iDg1217i3jfxmVk1Q=="], - - "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.11.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gzM+ZfIjfcCofwX/m1eLCoTT+3T70QLWaKDOW5Hf3+ddLlxMEVRIQtUoRsp0e/VFanr7u7VKS57TxhkRubseNg=="], - - "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.11.0", "", { "os": "linux", "cpu": "none" }, "sha512-oCR0ImJQhIwmqwNShsRT0tGIgKF5/H4nhtIEkQAQ9bLzMgjtRqIrZ3DtGHqd7w58zhXWfIZdyPNF9IrSm+J/fQ=="], - - "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.11.0", "", { "os": "linux", "cpu": "none" }, "sha512-MjCEqsUzXMfWPfsEUX+UXttzXz6xiNU11r7sj00C5og/UCyqYw1OjrbC/B1f/dloDpTn0rd4xy6c/LTvVQl2tg=="], - - "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.11.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-4TaTX7gT3357vWQsTe3IfDtWyJNe0FejypQ4ngwxB3v1IVaW6KAUt0huSvx/tmj+YWxd3zzXdWd8AzW0jo6dpg=="], - - "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.11.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ch1o3+tBra9vmrgXqrufVmYnvRPFlyUb7JWs/VXndBmyNSuP2KP+guAUrC0fr2aSGoOQOasAiZza7MTFU7Vrxg=="], - - "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.11.0", "", { "os": "linux", "cpu": "x64" }, "sha512-llTdl2gJAqXaGV7iV1w5BVlqXACcoT1YD3o840pCQx1ZmKKAAz7ydPnTjYVdkGImXNWPOIWJixHW0ryDm4Mx7w=="], - - "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.11.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-cROavohP0nX91NtIVVgOTugqoxlUSNxI9j7MD+B7fmD3gEFl8CVyTamR0/p6loDxLv51bQYTHRKn/ZYTd3ENzw=="], - - "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.11.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-6amVs34yHmxE6Q3CtTPXnSvIYGqwQJ/lVVRYccLzg9smge3WJ1knyBV5jpKKayp0n316uPYzB4EgEbgcuRvrPw=="], - - "@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.11.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-v/IZ5s2/3auHUoi0t6Ea1CDsWxrE9BvgvbDcJ04QX+nEbmTBazWPZeLsH8vWkRAh8EUKCZHXxjQsPhEH5Yk5pQ=="], - - "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.11.0", "", { "os": "win32", "cpu": "x64" }, "sha512-qvm+IQ6r2q4HZitSV69O+OmvCD1y4pH7SbhR6lPwLsfZS5QRHS8V20VHxmG1jJzSPPw7S8Bb1rdNcxDSqc4bYA=="], - "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], @@ -1135,12 +1085,6 @@ "@sqltools/formatter": ["@sqltools/formatter@1.2.5", "", {}, "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw=="], - "@swc-node/core": ["@swc-node/core@1.14.1", "", { "peerDependencies": { "@swc/core": ">= 1.13.3", "@swc/types": ">= 0.1" } }, "sha512-jrt5GUaZUU6cmMS+WTJEvGvaB6j1YNKPHPzC2PUi2BjaFbtxURHj6641Az6xN7b665hNniAIdvjxWcRml5yCnw=="], - - "@swc-node/register": ["@swc-node/register@1.11.1", "", { "dependencies": { "@swc-node/core": "^1.14.1", "@swc-node/sourcemap-support": "^0.6.1", "colorette": "^2.0.20", "debug": "^4.4.1", "oxc-resolver": "^11.6.1", "pirates": "^4.0.7", "tslib": "^2.8.1" }, "peerDependencies": { "@swc/core": ">= 1.4.13", "typescript": ">= 4.3" } }, "sha512-VQ0hJ5jX31TVv/fhZx4xJRzd8pwn6VvzYd2tGOHHr2TfXGCBixZoqdPDXTiEoJLCTS2MmvBf6zyQZZ0M8aGQCQ=="], - - "@swc-node/sourcemap-support": ["@swc-node/sourcemap-support@0.6.1", "", { "dependencies": { "source-map-support": "^0.5.21", "tslib": "^2.8.1" } }, "sha512-ovltDVH5QpdHXZkW138vG4+dgcNsxfwxHVoV6BtmTbz2KKl1A8ZSlbdtxzzfNjCjbpayda8Us9eMtcHobm38dA=="], - "@swc/cli": ["@swc/cli@0.7.8", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3", "tinyglobby": "^0.2.13" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-27Ov4rm0s2C6LLX+NDXfDVB69LGs8K94sXtFhgeUyQ4DBywZuCgTBu2loCNHRr8JhT9DeQvJM5j9FAu/THbo4w=="], "@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="], @@ -1189,8 +1133,6 @@ "@tsconfig/node16": ["@tsconfig/node16@1.0.4", "", {}, "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/accepts": ["@types/accepts@1.3.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -2851,8 +2793,6 @@ "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "oxc-resolver": ["oxc-resolver@11.11.0", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.11.0", "@oxc-resolver/binding-android-arm64": "11.11.0", "@oxc-resolver/binding-darwin-arm64": "11.11.0", "@oxc-resolver/binding-darwin-x64": "11.11.0", "@oxc-resolver/binding-freebsd-x64": "11.11.0", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.11.0", "@oxc-resolver/binding-linux-arm-musleabihf": "11.11.0", "@oxc-resolver/binding-linux-arm64-gnu": "11.11.0", "@oxc-resolver/binding-linux-arm64-musl": "11.11.0", "@oxc-resolver/binding-linux-ppc64-gnu": "11.11.0", "@oxc-resolver/binding-linux-riscv64-gnu": "11.11.0", "@oxc-resolver/binding-linux-riscv64-musl": "11.11.0", "@oxc-resolver/binding-linux-s390x-gnu": "11.11.0", "@oxc-resolver/binding-linux-x64-gnu": "11.11.0", "@oxc-resolver/binding-linux-x64-musl": "11.11.0", "@oxc-resolver/binding-wasm32-wasi": "11.11.0", "@oxc-resolver/binding-win32-arm64-msvc": "11.11.0", "@oxc-resolver/binding-win32-ia32-msvc": "11.11.0", "@oxc-resolver/binding-win32-x64-msvc": "11.11.0" } }, "sha512-vVeBJf77zBeqOA/LBCTO/pr0/ETHGSleCRsI5Kmsf2OsfB5opzhhZptt6VxkqjKWZH+eF1se88fYDG5DGRLjkg=="], - "p-cancelable": ["p-cancelable@3.0.0", "", {}, "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw=="], "p-event": ["p-event@4.2.0", "", { "dependencies": { "p-timeout": "^3.1.0" } }, "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ=="], diff --git a/database/package.json b/database/package.json index 2adcd10af..b22f9d95f 100644 --- a/database/package.json +++ b/database/package.json @@ -33,10 +33,6 @@ }, "devDependencies": { "@biomejs/biome": "2.0.0", - "@swc-node/register": "^1.10.10", - "@swc/cli": "^0.7.3", - "@swc/core": "^1.11.24", - "@swc/helpers": "^0.5.17", "@types/faker": "^5.5.9", "@types/geojson": "^7946.0.13", "@types/mysql": "^2.15.27", diff --git a/database/tsconfig.json b/database/tsconfig.json index ec6769fa2..862e9bf94 100644 --- a/database/tsconfig.json +++ b/database/tsconfig.json @@ -72,8 +72,5 @@ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, "references": [], /* Any project that is referenced must itself have a `references` array (which may be empty). */ - "ts-node": { - "swc": true - }, "exclude": ["**/*.test.ts", "**/*.spec.ts", "test/*"] } From 2d85b8b55bff7162d3e9088686ed4f531f4f5e88 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 22 Nov 2025 13:28:46 +0100 Subject: [PATCH 136/226] update readme that database will be now tests by bun --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9abb4eb90..2bc9c6a32 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,11 @@ describe('test', () => { ```ts import { clearLogs, printLogs } from 'config-schema/test/testSetup' ``` -- vitest (frontend, admin, database): +- vitest (frontend, admin): ```ts import { clearLogs, printLogs } from 'config-schema/test/testSetup.vitest' ``` -- bun (shared, core): +- bun (shared, core, database): ```ts import { clearLogs, printLogs } from 'config-schema/test/testSetup.bun' ``` From 99effdc2f35841cb453b373fb3497a2125f96df5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:42:28 +0100 Subject: [PATCH 137/226] move email into core, update packege, usw for it --- core/esbuild.config.ts | 16 + core/package.json | 7 +- core/src/config/index.ts | 26 + core/src/config/schema.ts | 87 + core/src/emails/README.md | 50 + .../sendEmailVariants.test.ts.snap | 1736 +++++++++++++++++ core/src/emails/index.ts | 1 + core/src/emails/locales/de.json | 101 + core/src/emails/locales/en.json | 104 + core/src/emails/localization.test.ts | 7 + core/src/emails/localization.ts | 31 + core/src/emails/sendEmailTranslated.test.ts | 153 ++ core/src/emails/sendEmailTranslated.ts | 122 ++ core/src/emails/sendEmailVariants.test.ts | 609 ++++++ core/src/emails/sendEmailVariants.ts | 179 ++ .../templates/accountActivation/html.pug | 18 + .../templates/accountActivation/subject.pug | 1 + .../accountMultiRegistration/html.pug | 22 + .../accountMultiRegistration/subject.pug | 1 + .../addedContributionMessage/html.pug | 16 + .../addedContributionMessage/subject.pug | 1 + .../contributionChangedByModerator/html.pug | 10 + .../subject.pug | 1 + .../templates/contributionConfirmed/html.pug | 10 + .../contributionConfirmed/subject.pug | 1 + .../templates/contributionDeleted/html.pug | 10 + .../templates/contributionDeleted/subject.pug | 1 + .../templates/contributionDenied/html.pug | 10 + .../templates/contributionDenied/subject.pug | 1 + .../src/emails/templates/includes/Chatbox.svg | 1 + .../templates/includes/answear_button.svg | 22 + .../templates/includes/chatbox-icon.png | Bin 0 -> 323 bytes .../templates/includes/chatbox-icon.pug | 6 + .../includes/contributionDetailsCTA.pug | 7 + .../emails/templates/includes/doNotReply.pug | 1 + core/src/emails/templates/includes/email.css | 216 ++ .../templates/includes/facebook-icon.png | Bin 0 -> 1449 bytes core/src/emails/templates/includes/footer.pug | 77 + .../templates/includes/gradido-header.jpeg | Bin 0 -> 9427 bytes .../emails/templates/includes/greeting.pug | 6 + core/src/emails/templates/includes/header.pug | 13 + .../templates/includes/requestNewLink.pug | 10 + .../emails/templates/includes/salutation.pug | 1 + .../templates/includes/telegram-icon.png | Bin 0 -> 2159 bytes .../templates/includes/twitter-icon.png | Bin 0 -> 2002 bytes .../src/emails/templates/includes/webflow.css | 166 ++ .../templates/includes/youtube-icon.png | Bin 0 -> 1802 bytes core/src/emails/templates/layout.pug | 26 + .../emails/templates/resetPassword/html.pug | 16 + .../templates/resetPassword/subject.pug | 1 + .../transactionLinkRedeemed/html.pug | 18 + .../transactionLinkRedeemed/subject.pug | 1 + .../templates/transactionReceived/html.pug | 30 + .../templates/transactionReceived/subject.pug | 1 + core/src/index.ts | 1 + core/src/types/images.d.ts | 14 + core/src/validation/user.test.ts | 27 +- core/tsconfig.json | 7 +- 58 files changed, 3989 insertions(+), 11 deletions(-) create mode 100644 core/esbuild.config.ts create mode 100644 core/src/emails/README.md create mode 100644 core/src/emails/__snapshots__/sendEmailVariants.test.ts.snap create mode 100644 core/src/emails/index.ts create mode 100644 core/src/emails/locales/de.json create mode 100644 core/src/emails/locales/en.json create mode 100644 core/src/emails/localization.test.ts create mode 100644 core/src/emails/localization.ts create mode 100644 core/src/emails/sendEmailTranslated.test.ts create mode 100644 core/src/emails/sendEmailTranslated.ts create mode 100644 core/src/emails/sendEmailVariants.test.ts create mode 100644 core/src/emails/sendEmailVariants.ts create mode 100644 core/src/emails/templates/accountActivation/html.pug create mode 100644 core/src/emails/templates/accountActivation/subject.pug create mode 100644 core/src/emails/templates/accountMultiRegistration/html.pug create mode 100644 core/src/emails/templates/accountMultiRegistration/subject.pug create mode 100644 core/src/emails/templates/addedContributionMessage/html.pug create mode 100644 core/src/emails/templates/addedContributionMessage/subject.pug create mode 100644 core/src/emails/templates/contributionChangedByModerator/html.pug create mode 100644 core/src/emails/templates/contributionChangedByModerator/subject.pug create mode 100644 core/src/emails/templates/contributionConfirmed/html.pug create mode 100644 core/src/emails/templates/contributionConfirmed/subject.pug create mode 100644 core/src/emails/templates/contributionDeleted/html.pug create mode 100644 core/src/emails/templates/contributionDeleted/subject.pug create mode 100644 core/src/emails/templates/contributionDenied/html.pug create mode 100644 core/src/emails/templates/contributionDenied/subject.pug create mode 100644 core/src/emails/templates/includes/Chatbox.svg create mode 100644 core/src/emails/templates/includes/answear_button.svg create mode 100644 core/src/emails/templates/includes/chatbox-icon.png create mode 100644 core/src/emails/templates/includes/chatbox-icon.pug create mode 100644 core/src/emails/templates/includes/contributionDetailsCTA.pug create mode 100644 core/src/emails/templates/includes/doNotReply.pug create mode 100644 core/src/emails/templates/includes/email.css create mode 100644 core/src/emails/templates/includes/facebook-icon.png create mode 100644 core/src/emails/templates/includes/footer.pug create mode 100644 core/src/emails/templates/includes/gradido-header.jpeg create mode 100644 core/src/emails/templates/includes/greeting.pug create mode 100644 core/src/emails/templates/includes/header.pug create mode 100644 core/src/emails/templates/includes/requestNewLink.pug create mode 100644 core/src/emails/templates/includes/salutation.pug create mode 100644 core/src/emails/templates/includes/telegram-icon.png create mode 100644 core/src/emails/templates/includes/twitter-icon.png create mode 100644 core/src/emails/templates/includes/webflow.css create mode 100644 core/src/emails/templates/includes/youtube-icon.png create mode 100644 core/src/emails/templates/layout.pug create mode 100644 core/src/emails/templates/resetPassword/html.pug create mode 100644 core/src/emails/templates/resetPassword/subject.pug create mode 100644 core/src/emails/templates/transactionLinkRedeemed/html.pug create mode 100644 core/src/emails/templates/transactionLinkRedeemed/subject.pug create mode 100644 core/src/emails/templates/transactionReceived/html.pug create mode 100644 core/src/emails/templates/transactionReceived/subject.pug create mode 100644 core/src/types/images.d.ts diff --git a/core/esbuild.config.ts b/core/esbuild.config.ts new file mode 100644 index 000000000..17435cef1 --- /dev/null +++ b/core/esbuild.config.ts @@ -0,0 +1,16 @@ +import { build } from 'esbuild' + +build({ + entryPoints: ['src/index.ts'], + outdir: 'build', + platform: 'node', + target: 'node18.20.7', + loader: { + '.png': 'dataurl', + '.jpeg': 'dataurl', + '.jpg': 'dataurl', + }, + bundle: true, + sourcemap: true, + packages: 'external', +}) diff --git a/core/package.json b/core/package.json index 3e444d5d5..06f6e7885 100644 --- a/core/package.json +++ b/core/package.json @@ -15,7 +15,7 @@ "license": "Apache-2.0", "private": true, "scripts": { - "build": "esbuild src/index.ts --outdir=build --platform=node --target=node18.20.7 --bundle --packages=external", + "build": "bun esbuild.config.ts", "build:bun": "bun build src/index.ts --outdir=build --target=bun --packages=external", "test": "bun test", "test:debug": "bun test --inspect-brk", @@ -26,20 +26,25 @@ }, "dependencies": { "database": "*", + "email-templates": "^10.0.1", "esbuild": "^0.25.2", "i18n": "^0.15.1", "joi": "^17.13.3", "jose": "^4.14.4", "log4js": "^6.9.1", + "nodemailer": "^6.6.5", + "pug": "^3.0.2", "shared": "*", "sodium-native": "^3.4.1", "zod": "^3.25.61" }, "devDependencies": { "@biomejs/biome": "2.0.0", + "@types/email-templates": "^10.0.4", "@types/i18n": "^0.13.4", "@types/minimatch": "6.0.0", "@types/node": "^17.0.21", + "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "config-schema": "*", "decimal.js-light": "^2.5.1", diff --git a/core/src/config/index.ts b/core/src/config/index.ts index 31b8cf033..be3179236 100644 --- a/core/src/config/index.ts +++ b/core/src/config/index.ts @@ -20,8 +20,34 @@ const federation = { ), } +const COMMUNITY_HOST = process.env.COMMUNITY_HOST ?? 'localhost' +const URL_PROTOCOL = process.env.URL_PROTOCOL ?? 'http' +const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNITY_HOST}` + +const community = { + COMMUNITY_SUPPORT_MAIL: process.env.COMMUNITY_SUPPORT_MAIL ?? 'support@supportmail.com', + COMMUNITY_URL, +} + + +const email = { + EMAIL: process.env.EMAIL === 'true', + EMAIL_LINK_FORGOTPASSWORD: + COMMUNITY_URL + (process.env.EMAIL_LINK_FORGOTPASSWORD_PATH ?? '/forgot-password'), + EMAIL_TLS: process.env.EMAIL_TLS !== 'false', + EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true', + EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER ?? 'stage1@gradido.net', + EMAIL_USERNAME: process.env.EMAIL_USERNAME ?? '', + EMAIL_SENDER: process.env.EMAIL_SENDER ?? 'info@gradido.net', + EMAIL_PASSWORD: process.env.EMAIL_PASSWORD ?? '', + EMAIL_SMTP_HOST: process.env.EMAIL_SMTP_HOST ?? 'mailserver', + EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025, +} + export const CONFIG = { ...federation, + ...community, + ...email, } validate(schema, CONFIG) diff --git a/core/src/config/schema.ts b/core/src/config/schema.ts index dbf6478de..6f8e2d6a8 100644 --- a/core/src/config/schema.ts +++ b/core/src/config/schema.ts @@ -1,6 +1,93 @@ + import Joi from 'joi' +import { COMMUNITY_SUPPORT_MAIL, COMMUNITY_URL, NODE_ENV } from 'config-schema' export const schema = Joi.object({ + COMMUNITY_SUPPORT_MAIL, + COMMUNITY_URL, + NODE_ENV, + + EMAIL: Joi.boolean() + .default(false) + .description('Enable or disable email functionality') + .required(), + + EMAIL_LINK_FORGOTPASSWORD: Joi.string() + .uri({ scheme: ['http', 'https'] }) + .custom((value: string, helpers: Joi.CustomHelpers): string | Joi.ErrorReport => { + if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) { + return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL }) + } + return value + }) + .description('Email Verification link for set new Password, when old Password was forgotten.') + .required(), + + EMAIL_TEST_MODUS: Joi.boolean() + .default(false) + .description('When enabled, all emails are sended to EMAIL_TEST_RECEIVER') + .optional(), + + EMAIL_TEST_RECEIVER: Joi.string() + .email() + .default('stage1@gradido.net') + .when('EMAIL_TEST_MODUS', { is: true, then: Joi.required() }) + .description('Email address used in test mode'), + + EMAIL_USERNAME: Joi.alternatives().conditional(Joi.ref('EMAIL'), { + is: true, + then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), { + is: 'development', + then: Joi.string() + .allow('') + .description('Username for SMTP authentication (optional in development)'), + otherwise: Joi.string() + .pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/) + .description('Valid SMTP username required in production') + .required(), + }), + otherwise: Joi.string().allow('').optional(), + }), + + EMAIL_SENDER: Joi.string() + .email() + .when('EMAIL', { is: true, then: Joi.required() }) + .default('info@gradido.net') + .description('Email address used as sender'), + + EMAIL_PASSWORD: Joi.alternatives().conditional(Joi.ref('EMAIL'), { + is: true, + then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), { + is: 'development', + then: Joi.string() + .allow('') + .description('Password for SMTP authentication (optional in development)'), + otherwise: Joi.string() + .min(8) + .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#]).{8,}$/) + .description( + 'Password must be at least 8 characters long, include uppercase and lowercase letters, a number, and a special character', + ) + .required(), + }), + otherwise: Joi.string().allow('').optional(), + }), + + EMAIL_SMTP_HOST: Joi.string() + .hostname() + .when('EMAIL', { is: true, then: Joi.required() }) + .default('mailserver') + .description('SMTP server hostname'), + + EMAIL_SMTP_PORT: Joi.number() + .integer() + .positive() + .when('EMAIL', { is: true, then: Joi.required() }) + .default(1025) + .description('SMTP server port'), + + EMAIL_TLS: Joi.boolean().default(true).description('Enable or disable TLS for SMTP').optional(), + FEDERATION_BACKEND_SEND_ON_API: Joi.string() .pattern(/^\d+_\d+$/) .default('1_0') diff --git a/core/src/emails/README.md b/core/src/emails/README.md new file mode 100644 index 000000000..9ab1d1124 --- /dev/null +++ b/core/src/emails/README.md @@ -0,0 +1,50 @@ +# Using `forwardemail`–`email-templates` With `pug` Package + +You'll find the GitHub repository of the `email-templates` package and the `pug` package here: + +- [email-templates](https://github.com/forwardemail/email-templates) +- [pug](https://www.npmjs.com/package/pug) + +## `pug` Documentation + +The full `pug` documentation you'll find here: + +- [pugjs.org](https://pugjs.org/) + +### Caching Possibility + +In case we are sending many emails in the future there is the possibility to cache the `pug` templates: + +- [cache-pug-templates](https://github.com/ladjs/cache-pug-templates) + +## Testing + +To test your send emails you have different possibilities: + +### In General + +To send emails to yourself while developing set in `.env` the value `EMAIL_TEST_MODUS=true` and `EMAIL_TEST_RECEIVER` to your preferred email address. + +### Unit Or Integration Tests + +To change the behavior to show previews etc. you have the following options to be set in `sendEmailTranslated.ts` on creating the email object: + +```js + const email = new Email({ + … + // send emails in development/test env: + send: true, + … + // to open send emails in the browser + preview: true, + // or + // to open send emails in a specific the browser + preview: { + open: { + app: 'firefox', + wait: false, + }, + }, + … + }) +``` diff --git a/core/src/emails/__snapshots__/sendEmailVariants.test.ts.snap b/core/src/emails/__snapshots__/sendEmailVariants.test.ts.snap new file mode 100644 index 000000000..0bf88e84d --- /dev/null +++ b/core/src/emails/__snapshots__/sendEmailVariants.test.ts.snap @@ -0,0 +1,1736 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`sendEmailVariants sendAccountActivationEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Email Verification

+
+

Hello Peter Lustig,

+

Your email address has just been registered with Gradido.

+
+
+

Complete registration

+
Please click here to complete the registration and activate your Gradido account.
Activate account +
Or copy the link into your browser window.
http://localhost/checkEmail/6627633878930542284 + +

Request new valid link

+
The link has a validity of 23 hours and 30 minutes. +If the validity of the link has already expired, you can have a new link sent to you here.
New link +
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTranslated" result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Try To Register Again With Your Email

+
+

Hello Peter Lustig,

+

Your email address has just been used again to register an account with Gradido.
However, an account already exists for your email address. +

+
+
+

Reset password

+
If you have forgotten your password, please click here.
reset +
Or copy the link into your browser window.
http://localhost/forgot-password +

Contact support

+
If you did not try to register again, please contact our support:
support@supportmail.com +
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendAddedContributionMessageEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Message about your common good contribution

+
+

Hello Peter Lustig,

+

You have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.

+
+
+

Read and reply to message

+
+

„My message.“

+

To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.

+
To account +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendContributionChangedByModeratorEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Your common good contribution has been changed

+
+

Hello Peter Lustig,

+

your common good contribution 'My contribution.' has just been changed by Bibi Bloxberg and now reads as 'This is a better contribution memo.'

+
+
+

Contribution details

+
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account +
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Your contribution to the common good was confirmed

+
+

Hello Peter Lustig,

+

Your common good contribution “My contribution.” has just been approved by Bibi Bloxberg. Your Gradido account has been credited with 23.54 GDD.

+
+
+

Contribution details

+
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account +
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendContributionDeletedEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Your common good contribution was deleted

+
+

Hello Peter Lustig,

+

Your common good contribution “My contribution.” was deleted by Bibi Bloxberg.

+
+
+

Contribution details

+
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account +
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendContributionDeniedEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Your common good contribution was rejected

+
+

Hello Peter Lustig,

+

Your common good contribution “My contribution.” was rejected by Bibi Bloxberg.

+
+
+

Contribution details

+
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account +
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendResetPasswordEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Reset password

+
+

Hello Peter Lustig,

+

You, or someone else, requested a password reset for this account.

+
+
+

Reset password

+
If it was you, please click here.
reset +
Or copy the link into your browser window.
http://localhost/reset-password/3762660021544901417 + +

Request new valid link

+
The link has a validity of 23 hours and 30 minutes. +If the validity of the link has already expired, you can have a new link sent to you here.
New link +
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Bibi Bloxberg has redeemed your Gradido link

+
+

Hello Peter Lustig,

+

Bibi Bloxberg (bibi@bloxberg.de) has just redeemed your link.

+
+
+

Transaction details

+
Amount: 17.65 GDD
Message: You deserve it! 🙏🏼
You can find transaction details in your Gradido account. +
To account +
Please do not reply to this email.
+
+
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; + +exports[`sendEmailVariants sendTransactionReceivedEmail result has the correct html as snapshot 1`] = ` +" + + + + + + + + +
+
+
\"Gradido
+
+
+

Bibi Bloxberg has sent you 37.40 Gradido

+
+

Hello Peter Lustig,

+

You have just received 37.40 GDD from Bibi Bloxberg (bibi@bloxberg.de). +

+
+
+

Message

+
+
Du bist schon lustiger ;)
+
+ +
To account +
+

Kind regards,
your Gradido team +

+
+
+
+
+
\"facebook\"\"Telegram\"\"Twitter\"\"youtube\"
+
+
+
If you have any further questions, please contact our support.
support@gradido.net +
\"Gradido
+
Privacy Policy +
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


+
+
+
+
+ +" +`; diff --git a/core/src/emails/index.ts b/core/src/emails/index.ts new file mode 100644 index 000000000..e7b39331a --- /dev/null +++ b/core/src/emails/index.ts @@ -0,0 +1 @@ +export * from './sendEmailVariants' \ No newline at end of file diff --git a/core/src/emails/locales/de.json b/core/src/emails/locales/de.json new file mode 100644 index 000000000..8b34f61f4 --- /dev/null +++ b/core/src/emails/locales/de.json @@ -0,0 +1,101 @@ +{ + "emails": { + "accountActivation": { + "activateAccount": "Konto aktivieren", + "emailRegistered": "deine E-Mail-Adresse wurde soeben bei Gradido registriert.", + "pleaseClickLink": "Klicke bitte hier, um die Registrierung abzuschließen und dein Gradido-Konto zu aktivieren.", + "subject": "E-Mail Überprüfung", + "title": "E-Mail Überprüfung" + }, + "accountMultiRegistration": { + "contactSupport": "Support kontaktieren", + "emailExists": "Es existiert jedoch zu deiner E-Mail-Adresse schon ein Konto.", + "emailReused": "deine E-Mail-Adresse wurde soeben erneut benutzt, um bei Gradido ein Konto zu registrieren.", + "ifYouAreNotTheOne": "Wenn du nicht versucht hast dich erneut zu registrieren, wende dich bitte an unseren Support:", + "onForgottenPasswordClickLink": "Solltest du dein Passwort vergessen haben, klicke bitte hier.", + "subject": "Erneuter Registrierungsversuch mit deiner E-Mail", + "title": "Erneuter Registrierungsversuch mit deiner E-Mail" + }, + "addedContributionMessage": { + "commonGoodContributionMessage": "du hast zu deinem Gemeinwohl-Beitrag „{contributionMemo}“ eine Nachricht von {senderFirstName} {senderLastName} erhalten.", + "readMessage": "Nachricht lesen und beantworten", + "subject": "Nachricht zu deinem Gemeinwohl-Beitrag", + "title": "Nachricht zu deinem Gemeinwohl-Beitrag", + "message": "„{message}“", + "toSeeAndAnswerMessage": "Um auf die Nachricht zu antworten, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“." + }, + "contribution": { + "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“." + }, + "contributionChangedByModerator": { + "subject": "Dein Gemeinwohl-Beitrag wurde geändert", + "text": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} geändert und lautet jetzt „{contributionMemoUpdated}“", + "title": "Dein Gemeinwohl-Beitrag wurde geändert" + }, + "contributionConfirmed": { + "commonGoodContributionConfirmed": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} bestätigt. Es wurden deinem Gradido-Konto {amountGDD} GDD gutgeschrieben.", + "subject": "Dein Gemeinwohl-Beitrag wurde bestätigt", + "title": "Dein Gemeinwohl-Beitrag wurde bestätigt" + }, + "contributionDeleted": { + "commonGoodContributionDeleted": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} gelöscht.", + "subject": "Dein Gemeinwohl-Beitrag wurde gelöscht", + "title": "Dein Gemeinwohl-Beitrag wurde gelöscht" + }, + "contributionDenied": { + "commonGoodContributionDenied": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} abgelehnt.", + "subject": "Dein Gemeinwohl-Beitrag wurde abgelehnt", + "title": "Dein Gemeinwohl-Beitrag wurde abgelehnt" + }, + "footer": { + "contactOurSupport": "Bei weiteren Fragen kontaktiere bitte unseren Support.", + "imprint": "Impressum", + "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", + "imprintImageAlt": "Gradido-Akademie Logo", + "privacyPolicy": "Datenschutzerklärung", + "supportEmail": "support@gradido.net" + }, + "general": { + "amountGDD": "Betrag: {amountGDD} GDD", + "answerNow": "Jetzt antworten", + "completeRegistration": "Registrierung abschließen", + "contribution": "Gemeinwohl-Beitrag: {contributionMemo}", + "contributionDetails": "Beitragsdetails", + "detailsYouFindOnLinkToYourAccount": "Details zur Transaktion findest du in deinem Gradido-Konto.", + "helloName": "Hallo {firstName} {lastName},", + "linkValidity": "Der Link hat eine Gültigkeit von {hours} Stunden.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.", + "linkValidityWithMinutes": "Der Link hat eine Gültigkeit von {hours} Stunden und {minutes} Minuten.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.", + "message": "Nachricht", + "newLink": "Neuer Link", + "orCopyLink": "Oder kopiere den Link in dein Browserfenster.", + "pleaseDoNotReply": "Bitte antworte nicht auf diese E-Mail.", + "requestNewLink": "Neuen gültigen Link anfordern", + "reset": "zurücksetzen", + "sincerelyYours": "Liebe Grüße", + "toAccount": "Zum Konto", + "transactionDetails": "Transaktionsdetails", + "yourGradidoTeam": "dein Gradido-Team" + }, + "resetPassword": { + "pleaseClickLink": "Wenn du es warst, klicke bitte hier.", + "subject": "Passwort zurücksetzen", + "title": "Passwort zurücksetzen", + "youOrSomeoneResetPassword": "du oder jemand anderes, hast für dieses Konto ein Zurücksetzen des Passworts angefordert." + }, + "transactionLinkRedeemed": { + "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) hat soeben deinen Link eingelöst.", + "memo": "Nachricht: {transactionMemo}", + "subject": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst", + "title": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst" + }, + "transactionReceived": { + "haveReceivedAmountGDDFrom": "du hast soeben {transactionAmount} GDD erhalten von {senderFirstName} {senderLastName}", + "subject": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet", + "replySubject": "Re: {senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet", + "title": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet" + } + }, + "general": { + "decimalSeparator": "," + } +} diff --git a/core/src/emails/locales/en.json b/core/src/emails/locales/en.json new file mode 100644 index 000000000..cc8d59c75 --- /dev/null +++ b/core/src/emails/locales/en.json @@ -0,0 +1,104 @@ +{ + "emails": { + "accountActivation": { + "activateAccount": "Activate account", + "emailRegistered": "Your email address has just been registered with Gradido.", + "pleaseClickLink": "Please click here to complete the registration and activate your Gradido account.", + "subject": "Email Verification", + "title": "Email Verification" + }, + "accountMultiRegistration": { + "contactSupport": "Contact support", + "emailExists": "However, an account already exists for your email address.", + "emailReused": "Your email address has just been used again to register an account with Gradido.", + "ifYouAreNotTheOne": "If you did not try to register again, please contact our support:", + "onForgottenPasswordClickLink": "If you have forgotten your password, please click here.", + "subject": "Try To Register Again With Your Email", + "title": "Try To Register Again With Your Email" + }, + "addedContributionMessage": { + "commonGoodContributionMessage": "You have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.", + "readMessage": "Read and reply to message", + "subject": "Message about your common good contribution", + "title": "Message about your common good contribution", + "message": "„{message}“", + "toSeeAndAnswerMessage": "To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." + }, + "contribution": { + "toSeeContributionsAndMessages": "To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." + }, + "contributionChangedByModerator": { + "subject": "Your common good contribution has been changed", + "text": "your common good contribution '{contributionMemo}' has just been changed by {senderFirstName} {senderLastName} and now reads as '{contributionMemoUpdated}'", + "title": "Your common good contribution has been changed" + }, + "contributionConfirmed": { + "commonGoodContributionConfirmed": "Your common good contribution “{contributionMemo}” has just been approved by {senderFirstName} {senderLastName}. Your Gradido account has been credited with {amountGDD} GDD.", + "subject": "Your contribution to the common good was confirmed", + "title": "Your contribution to the common good was confirmed" + }, + "contributionDeleted": { + "commonGoodContributionDeleted": "Your common good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.", + "subject": "Your common good contribution was deleted", + "title": "Your common good contribution was deleted" + }, + "contributionDenied": { + "commonGoodContributionDenied": "Your common good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.", + "subject": "Your common good contribution was rejected", + "title": "Your common good contribution was rejected" + }, + "footer": { + "contactOurSupport": "If you have any further questions, please contact our support.", + "imprint": "Impressum", + "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", + "imprintImageAlt": "Gradido-Akademie Logo", + "privacyPolicy": "Privacy Policy", + "supportEmail": "support@gradido.net" + }, + "general": { + "amountGDD": "Amount: {amountGDD} GDD", + "answerNow": "Reply", + "completeRegistration": "Complete registration", + "contribution": "Contribution: : {contributionMemo}", + "contributionDetails": "Contribution details", + "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account.", + "helloName": "Hello {firstName} {lastName},", + "linkValidity": "The link has a validity of {hours} hours.\nIf the validity of the link has already expired, you can have a new link sent to you here.", + "linkValidityWithMinutes": "The link has a validity of {hours} hours and {minutes} minutes.\nIf the validity of the link has already expired, you can have a new link sent to you here.", + "message": "Message", + "newLink": "New link", + "orCopyLink": "Or copy the link into your browser window.", + "pleaseDoNotReply": "Please do not reply to this email.", + "requestNewLink": "Request new valid link", + "reset": "reset", + "sincerelyYours": "Kind regards,", + "toAccount": "To account", + "transactionDetails": "Transaction details", + "yourGradidoTeam": "your Gradido team" + }, + "resetPassword": { + "pleaseClickLink": "If it was you, please click here.", + "subject": "Reset password", + "title": "Reset password", + "youOrSomeoneResetPassword": "You, or someone else, requested a password reset for this account." + }, + "transactionLinkRedeemed": { + "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) has just redeemed your link.", + "memo": "Message: {transactionMemo}", + "subject": "{senderFirstName} {senderLastName} has redeemed your Gradido link", + "title": "{senderFirstName} {senderLastName} has redeemed your Gradido link" + }, + "transactionReceived": { + "haveReceivedAmountGDDFrom": "You have just received {transactionAmount} GDD from {senderFirstName} {senderLastName}", + "replySubject": "RE: {senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", + "subject": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", + "title": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido" + } + }, + "general": { + "decimalSeparator": "." + }, + "accountMultiRegistration": { + "contactSupport": "accountMultiRegistration.contactSupport" + } +} \ No newline at end of file diff --git a/core/src/emails/localization.test.ts b/core/src/emails/localization.test.ts new file mode 100644 index 000000000..77651c4e4 --- /dev/null +++ b/core/src/emails/localization.test.ts @@ -0,0 +1,7 @@ +import { i18n } from './localization' + +describe('localization', () => { + it('translate emails.accountMultiRegistration.contactSupport with Contact support', () => { + expect(i18n.__('emails.accountMultiRegistration.contactSupport')).toBe('Contact support') + }) +}) \ No newline at end of file diff --git a/core/src/emails/localization.ts b/core/src/emails/localization.ts new file mode 100644 index 000000000..488ae5411 --- /dev/null +++ b/core/src/emails/localization.ts @@ -0,0 +1,31 @@ +import en from './locales/en.json' +import de from './locales/de.json' +import { I18n } from 'i18n' + +function flatten(obj: any, prefix: string = ''): any { + const result: any = {} + for (const key in obj) { + if (typeof obj[key] === 'object' && obj[key] !== null) { + Object.assign(result, flatten(obj[key], prefix + key + '.')) + } else { + result[prefix + key] = obj[key] + } + } + return result +} + +export const i18n = new I18n({ + locales: ['en', 'de'], + defaultLocale: 'en', + staticCatalog: { en: flatten(en), de: flatten(de) }, + api: { + __: 't', // now req.__ becomes req.t + __n: 'tn', // and req.__n can be called as req.tn + }, + register: global, + mustacheConfig: { + tags: ['{', '}'], + disable: false, + }, +}) + diff --git a/core/src/emails/sendEmailTranslated.test.ts b/core/src/emails/sendEmailTranslated.test.ts new file mode 100644 index 000000000..3f8b5680e --- /dev/null +++ b/core/src/emails/sendEmailTranslated.test.ts @@ -0,0 +1,153 @@ +import { createTransport } from 'nodemailer' +import { CONFIG } from '../config' +import { i18n } from './localization' +import { getLogger } from '../../../config-schema/test/testSetup.bun' +import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const' +import { sendEmailTranslated } from './sendEmailTranslated' +import { mock, jest, describe, it, expect, beforeEach, afterAll } from 'bun:test' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`) + +const testMailServerHost = 'localhost' +const testMailServerPort = 1025 + +CONFIG.EMAIL = false +CONFIG.EMAIL_SMTP_HOST = testMailServerHost +CONFIG.EMAIL_SMTP_PORT = testMailServerPort +CONFIG.EMAIL_SENDER = 'info@gradido.net' +CONFIG.EMAIL_USERNAME = 'user' +CONFIG.EMAIL_PASSWORD = 'pwd' +CONFIG.EMAIL_TLS = true + +mock.module('nodemailer', () => { + return { + createTransport: jest.fn(() => { + return { + sendMail: () => { + return { + messageId: 'message', + } + }, + } + }), + } +}) + +afterAll(() => { + jest.restoreAllMocks() +}) + +const spySetLocale = jest.spyOn(i18n, 'setLocale') +const spyTranslate = jest.spyOn(i18n, '__') + +describe('sendEmailTranslated', () => { + let result: Record | boolean | null + + describe('config email is false', () => { + beforeEach(async () => { + result = await sendEmailTranslated({ + receiver: { + to: 'receiver@mail.org', + cc: 'support@gradido.net', + }, + template: 'accountMultiRegistration', + locals: { + language: 'en', + }, + }) + }) + + it('logs warning', () => { + expect(logger.info).toBeCalledWith('Emails are disabled via config...') + }) + + it('returns false', () => { + expect(result).toBeFalsy() + }) + }) + + describe('config email is true', () => { + beforeEach(async () => { + CONFIG.EMAIL = true + result = await sendEmailTranslated({ + receiver: { + to: 'receiver@mail.org', + cc: 'support@gradido.net', + }, + template: 'accountMultiRegistration', + locals: { + language: 'en', + }, + }) + }) + + it('calls the transporter', () => { + expect(createTransport).toBeCalledWith({ + host: testMailServerHost, + port: testMailServerPort, + secure: false, + requireTLS: true, + auth: { + user: 'user', + pass: 'pwd', + }, + }) + }) + + describe('call of "sendEmailTranslated"', () => { + it('has expected result', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'receiver@mail.org', + cc: 'support@gradido.net', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Try To Register Again With Your Email', + html: expect.stringContaining('Try To Register Again With Your Email'), + text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), + }), + }) + }) + }) + + it('calls "i18n.setLocale" with "en"', async () => { + expect(spySetLocale).toBeCalledWith('en') + }) + + it('calls "i18n.__" for translation', () => { + expect(spyTranslate).toBeCalled() + }) + }) + + describe('with email EMAIL_TEST_MODUS true', () => { + beforeEach(async () => { + jest.clearAllMocks() + CONFIG.EMAIL = true + CONFIG.EMAIL_TEST_MODUS = true + result = await sendEmailTranslated({ + receiver: { + to: 'receiver@mail.org', + cc: 'support@gradido.net', + }, + template: 'accountMultiRegistration', + locals: { + language: 'en', + }, + }) + }) + + it('call of "sendEmailTranslated" with faked "to"', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: CONFIG.EMAIL_TEST_RECEIVER, + cc: 'support@gradido.net', + from: `Gradido (emails.general.doNotAnswer) <${CONFIG.EMAIL_SENDER}>`, + attachments: expect.any(Array), + subject: 'Try To Register Again With Your Email', + html: expect.stringContaining('Try To Register Again With Your Email'), + text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), + }), + }) + }) + }) +}) diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts new file mode 100644 index 000000000..02d6de130 --- /dev/null +++ b/core/src/emails/sendEmailTranslated.ts @@ -0,0 +1,122 @@ +import path from 'path' + +import Email from 'email-templates' +import { i18n } from './localization' +import { createTransport } from 'nodemailer' +import { CONFIG } from '../config' +import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const' +import { getLogger } from 'log4js' +import gradidoHeader from './templates/includes/gradido-header.jpeg' +import facebookIcon from './templates/includes/facebook-icon.png' +import telegramIcon from './templates/includes/telegram-icon.png' +import twitterIcon from './templates/includes/twitter-icon.png' +import youtubeIcon from './templates/includes/youtube-icon.png' +import chatboxIcon from './templates/includes/chatbox-icon.png' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`) + +export const sendEmailTranslated = async ({ + receiver, + template, + locals, +}: { + receiver: { + to: string + cc?: string + } + template: string + locals: Record +}): Promise | boolean | null> => { + // TODO: test the calling order of 'i18n.setLocale' for example: language of logging 'en', language of email receiver 'es', reset language of current user 'de' + + if (!CONFIG.EMAIL) { + logger.info(`Emails are disabled via config...`) + return null + } + + // because language of receiver can differ from language of current user who triggers the sending + // const rememberLocaleToRestore = i18n.getLocale() + i18n.setLocale('en') // for logging + logger.info( + `send Email: language=${locals.locale as string} to=${receiver.to.substring(0, 3)}...` + + (receiver.cc ? `, cc=${receiver.cc.substring(0, 3)}...` : '') + + `, subject=${i18n.__('emails.' + template + '.subject')}`, + ) + + if (CONFIG.EMAIL_TEST_MODUS) { + logger.info( + `Testmodus=ON: change receiver from ${receiver.to} to ${CONFIG.EMAIL_TEST_RECEIVER}`, + ) + receiver.to = CONFIG.EMAIL_TEST_RECEIVER + } + + const transport = createTransport({ + host: CONFIG.EMAIL_SMTP_HOST, + port: CONFIG.EMAIL_SMTP_PORT, + secure: false, // true for 465, false for other ports + requireTLS: CONFIG.EMAIL_TLS, + auth: { + user: CONFIG.EMAIL_USERNAME, + pass: CONFIG.EMAIL_PASSWORD, + }, + }) + i18n.setLocale(locals.language as string) // for email + + // TESTING: see 'README.md' + const email = new Email({ + message: { + from: `Gradido (${i18n.__('emails.general.doNotAnswer')}) <${CONFIG.EMAIL_SENDER}>`, + }, + send: CONFIG.EMAIL, + transport, + preview: false, + }) + + const resultSend = await email + .send({ + template: path.join(__dirname, 'templates', template), + message: { + ...receiver, + attachments: [ + { + // filename: 'gradido-header.jpeg', + content: gradidoHeader, + cid: 'gradidoheader', + }, + { + // filename: 'facebook-icon.png', + content: facebookIcon, + cid: 'facebookicon', + }, + { + // filename: 'telegram-icon.png', + content: telegramIcon, + cid: 'telegramicon', + }, + { + // filename: 'twitter-icon.png', + content: twitterIcon, + cid: 'twittericon', + }, + { + // filename: 'youtube-icon.png', + content: youtubeIcon, + cid: 'youtubeicon', + }, + { + // filename: 'chatbox-icon.png', + content: chatboxIcon, + cid: 'chatboxicon', + }, + ], + }, + locals, // the 'locale' in here seems not to be used by 'email-template', because it doesn't work if the language isn't set before by 'i18n.setLocale' + // t: i18n.__.bind(i18n), + }) + .catch((error: unknown) => { + logger.error('Error sending notification email', error) + return error + }) + + return resultSend +} diff --git a/core/src/emails/sendEmailVariants.test.ts b/core/src/emails/sendEmailVariants.test.ts new file mode 100644 index 000000000..74743dbd9 --- /dev/null +++ b/core/src/emails/sendEmailVariants.test.ts @@ -0,0 +1,609 @@ +import { Decimal } from 'decimal.js-light' +import { CONFIG } from '../config' + +import * as sendEmailTranslatedApi from './sendEmailTranslated' +import { + sendAccountActivationEmail, + sendAccountMultiRegistrationEmail, + sendAddedContributionMessageEmail, + sendContributionChangedByModeratorEmail, + sendContributionConfirmedEmail, + sendContributionDeletedEmail, + sendContributionDeniedEmail, + sendResetPasswordEmail, + sendTransactionLinkRedeemedEmail, + sendTransactionReceivedEmail, +} from './sendEmailVariants' + +const testMailServerHost = 'localhost' +const testMailServerPort = 1025 +const testMailTLS = false + +CONFIG.EMAIL = true +CONFIG.EMAIL_SENDER = 'info@gradido.net' +CONFIG.EMAIL_SMTP_HOST = testMailServerHost +CONFIG.EMAIL_SMTP_PORT = testMailServerPort +CONFIG.EMAIL_TLS = testMailTLS + +jest.mock('nodemailer', () => { + return { + __esModule: true, + createTransport: jest.fn(() => { + return { + sendMail: () => { + return { + messageId: 'message', + } + }, + } + }), + } +}) + +const sendEmailTranslatedSpy = jest.spyOn(sendEmailTranslatedApi, 'sendEmailTranslated') + +describe('sendEmailVariants', () => { + let result: any + const contributionFrontendLink = + 'https://gradido.net/contributions/own-contributions/1#contributionListItem-1' + + describe('sendAddedContributionMessageEmail', () => { + beforeAll(async () => { + result = await sendAddedContributionMessageEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + message: 'My message.', + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'addedContributionMessage', + locals: expect.objectContaining({ + firstName: 'Peter', + lastName: 'Lustig', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + message: 'My message.', + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + }), + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + // bun testrunner bug, toMatchObject mess with 'result' + const resultClone = JSON.parse(JSON.stringify(result)) + expect(resultClone).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Message about your common good contribution', + html: expect.any(String), + text: expect.stringContaining('MESSAGE ABOUT YOUR COMMON GOOD CONTRIBUTION'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendAccountActivationEmail', () => { + beforeAll(async () => { + result = await sendAccountActivationEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + activationLink: 'http://localhost/checkEmail/6627633878930542284', + timeDurationObject: { hours: 23, minutes: 30 }, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'accountActivation', + locals: expect.objectContaining({ + firstName: 'Peter', + lastName: 'Lustig', + language: 'en', + activationLink: 'http://localhost/checkEmail/6627633878930542284', + timeDurationObject: { hours: 23, minutes: 30 }, + resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }), + }) + }) + }) + + + describe('result', () => { + it('is the expected object', () => { + // bun testrunner bug, toMatchObject mess with 'result' + const resultClone = JSON.parse(JSON.stringify(result)) + expect(resultClone).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Email Verification', + html: expect.any(String), + text: expect.stringContaining('EMAIL VERIFICATION'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + /* + + describe('sendAccountMultiRegistrationEmail', () => { + beforeAll(async () => { + result = await sendAccountMultiRegistrationEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'accountMultiRegistration', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Try To Register Again With Your Email', + html: expect.any(String), + text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + }) + + describe('sendContributionConfirmedEmail', () => { + beforeAll(async () => { + result = await sendContributionConfirmedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionAmount: new Decimal(23.54), + contributionFrontendLink, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'contributionConfirmed', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionAmount: '23.54', + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + contributionFrontendLink, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Your contribution to the common good was confirmed', + html: expect.any(String), + text: expect.stringContaining('YOUR CONTRIBUTION TO THE COMMON GOOD WAS CONFIRMED'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendContributionChangedByModeratorEmail', () => { + beforeAll(async () => { + result = await sendContributionChangedByModeratorEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionMemoUpdated: 'This is a better contribution memo.', + contributionFrontendLink, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'contributionChangedByModerator', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionMemoUpdated: 'This is a better contribution memo.', + contributionFrontendLink, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Your common good contribution has been changed', + html: expect.any(String), + text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION HAS BEEN CHANGED'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendContributionDeniedEmail', () => { + beforeAll(async () => { + result = await sendContributionDeniedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'contributionDenied', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + }, + }) + }) + }) + + describe('result', () => { + it('has expected result', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Your common good contribution was rejected', + html: expect.any(String), + text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS REJECTED'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendContributionDeletedEmail', () => { + beforeAll(async () => { + result = await sendContributionDeletedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'contributionDeleted', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + contributionMemo: 'My contribution.', + contributionFrontendLink, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Your common good contribution was deleted', + html: expect.any(String), + text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS DELETED'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendResetPasswordEmail', () => { + beforeAll(async () => { + result = await sendResetPasswordEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + resetLink: 'http://localhost/reset-password/3762660021544901417', + timeDurationObject: { hours: 23, minutes: 30 }, + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'resetPassword', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + resetLink: 'http://localhost/reset-password/3762660021544901417', + timeDurationObject: { hours: 23, minutes: 30 }, + resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Reset password', + html: expect.any(String), + text: expect.stringContaining('RESET PASSWORD'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendTransactionLinkRedeemedEmail', () => { + beforeAll(async () => { + result = await sendTransactionLinkRedeemedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + senderEmail: 'bibi@bloxberg.de', + transactionMemo: 'You deserve it! 🙏🏼', + transactionAmount: new Decimal(17.65), + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'transactionLinkRedeemed', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + senderEmail: 'bibi@bloxberg.de', + transactionMemo: 'You deserve it! 🙏🏼', + transactionAmount: '17.65', + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Bibi Bloxberg has redeemed your Gradido link', + html: expect.any(String), + text: expect.stringContaining('BIBI BLOXBERG HAS REDEEMED YOUR GRADIDO LINK'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + + describe('sendTransactionReceivedEmail', () => { + beforeAll(async () => { + result = await sendTransactionReceivedEmail({ + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + language: 'en', + memo: 'Du bist schon lustiger ;)', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + senderEmail: 'bibi@bloxberg.de', + transactionAmount: new Decimal(37.4), + }) + }) + + describe('calls "sendEmailTranslated"', () => { + it('with expected parameters', () => { + expect(sendEmailTranslatedSpy).toBeCalledWith({ + receiver: { + to: 'Peter Lustig ', + }, + template: 'transactionReceived', + locals: { + firstName: 'Peter', + lastName: 'Lustig', + locale: 'en', + memo: 'Du bist schon lustiger ;)', + senderFirstName: 'Bibi', + senderLastName: 'Bloxberg', + senderEmail: 'bibi@bloxberg.de', + transactionAmount: '37.40', + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + communityURL: CONFIG.COMMUNITY_URL, + }, + }) + }) + }) + + describe('result', () => { + it('is the expected object', () => { + expect(result).toMatchObject({ + originalMessage: expect.objectContaining({ + to: 'Peter Lustig ', + from: 'Gradido (emails.general.doNotAnswer) ', + attachments: expect.any(Array), + subject: 'Bibi Bloxberg has sent you 37.40 Gradido', + html: expect.any(String), + text: expect.stringContaining('BIBI BLOXBERG HAS SENT YOU 37.40 GRADIDO'), + }), + }) + }) + + it('has the correct html as snapshot', () => { + expect(result.originalMessage.html).toMatchSnapshot() + }) + }) + }) + */ +}) diff --git a/core/src/emails/sendEmailVariants.ts b/core/src/emails/sendEmailVariants.ts new file mode 100644 index 000000000..75f5c468d --- /dev/null +++ b/core/src/emails/sendEmailVariants.ts @@ -0,0 +1,179 @@ +import { Decimal } from 'decimal.js-light' + +import { CONFIG } from '../config' +import { decimalSeparatorByLanguage } from 'core' + +import { sendEmailTranslated } from './sendEmailTranslated' + +export interface EmailCommonData { + firstName: string + lastName: string + email: string + language: string +} + +export interface ContributionEmailCommonData { + senderFirstName: string + senderLastName: string + contributionMemo: string + contributionFrontendLink: string +} + +function getEmailCommonLocales(): Record { + return { + supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, + resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, + communityURL: CONFIG.COMMUNITY_URL, + } +} + +export const sendAddedContributionMessageEmail = ( + data: EmailCommonData & ContributionEmailCommonData & { + message: string + }, +): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { + to: `${data.firstName} ${data.lastName} <${data.email}>`, + }, + template: 'addedContributionMessage', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendAccountActivationEmail = (data: EmailCommonData & { + activationLink: string + timeDurationObject: Record + logoUrl?: string | null +}): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'accountActivation', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendAccountMultiRegistrationEmail = (data: EmailCommonData): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'accountMultiRegistration', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendContributionConfirmedEmail = ( + data: EmailCommonData & ContributionEmailCommonData & { + contributionAmount: Decimal + }, +): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'contributionConfirmed', + locals: { + ...data, + ...getEmailCommonLocales(), + contributionAmount: decimalSeparatorByLanguage(data.contributionAmount, data.language), + }, + }) +} + +export const sendContributionChangedByModeratorEmail = ( + data: EmailCommonData & ContributionEmailCommonData & { + contributionMemoUpdated: string + }, +): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'contributionChangedByModerator', + locals: { + ...data, + ...getEmailCommonLocales(), + contributionMemoUpdated: data.contributionMemoUpdated, + }, + }) +} + +export const sendContributionDeletedEmail = ( + data: EmailCommonData & ContributionEmailCommonData, +): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'contributionDeleted', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendContributionDeniedEmail = ( + data: EmailCommonData & ContributionEmailCommonData, +): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'contributionDenied', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendResetPasswordEmail = (data: EmailCommonData & { + resetLink: string + timeDurationObject: Record +}): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'resetPassword', + locals: { + ...data, + ...getEmailCommonLocales(), + }, + }) +} + +export const sendTransactionLinkRedeemedEmail = (data: EmailCommonData & { + senderFirstName: string + senderLastName: string + senderEmail: string + transactionMemo: string + transactionAmount: Decimal +}): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'transactionLinkRedeemed', + locals: { + ...data, + transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language), + ...getEmailCommonLocales(), + }, + }) +} + +export const sendTransactionReceivedEmail = (data: EmailCommonData & { + senderFirstName: string + senderLastName: string + senderEmail: string + memo: string + transactionAmount: Decimal +}): Promise | boolean | null> => { + return sendEmailTranslated({ + receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, + template: 'transactionReceived', + locals: { + ...data, + transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language), + ...getEmailCommonLocales(), + }, + }) +} diff --git a/core/src/emails/templates/accountActivation/html.pug b/core/src/emails/templates/accountActivation/html.pug new file mode 100644 index 000000000..6b5dd41c3 --- /dev/null +++ b/core/src/emails/templates/accountActivation/html.pug @@ -0,0 +1,18 @@ +extend ../layout.pug + +block content + if logoUrl + img(src=logoUrl, alt="Banner", style="max-width: 680px; max-height: 250px;border-radius:20px") + h2= t('emails.accountActivation.title') + .text-block + include ../includes/salutation.pug + p= t('emails.accountActivation.emailRegistered') + .content + h2= t('emails.general.completeRegistration') + div(class="p_content")= t('emails.accountActivation.pleaseClickLink') + a.button-3(href=activationLink) #{t('emails.accountActivation.activateAccount')} + div(class="p_content")= t('emails.general.orCopyLink') + + a.clink(href=activationLink) #{activationLink} + + include ../includes/requestNewLink.pug diff --git a/core/src/emails/templates/accountActivation/subject.pug b/core/src/emails/templates/accountActivation/subject.pug new file mode 100644 index 000000000..81749a38e --- /dev/null +++ b/core/src/emails/templates/accountActivation/subject.pug @@ -0,0 +1 @@ += t('emails.accountActivation.subject') diff --git a/core/src/emails/templates/accountMultiRegistration/html.pug b/core/src/emails/templates/accountMultiRegistration/html.pug new file mode 100644 index 000000000..4d568261b --- /dev/null +++ b/core/src/emails/templates/accountMultiRegistration/html.pug @@ -0,0 +1,22 @@ +extend ../layout.pug + +block content + h2= t('emails.accountMultiRegistration.title') + .text-block + include ../includes/salutation.pug + p + = t('emails.accountMultiRegistration.emailReused') + br + = t('emails.accountMultiRegistration.emailExists') + .content + h2= t('emails.resetPassword.title') + div(class="p_content")= t('emails.accountMultiRegistration.onForgottenPasswordClickLink') + a.button-3(href=resendLink) #{t('emails.general.reset')} + div(class="p_content")= t('emails.general.orCopyLink') + + a.clink(href=resendLink) #{resendLink} + + h2(style="color: red")= t('emails.accountMultiRegistration.contactSupport') + div(class="p_content")= t('emails.accountMultiRegistration.ifYouAreNotTheOne') + + a.clink(href='mailto:' + supportEmail)= supportEmail diff --git a/core/src/emails/templates/accountMultiRegistration/subject.pug b/core/src/emails/templates/accountMultiRegistration/subject.pug new file mode 100644 index 000000000..fb130f0e4 --- /dev/null +++ b/core/src/emails/templates/accountMultiRegistration/subject.pug @@ -0,0 +1 @@ += t('emails.accountMultiRegistration.subject') diff --git a/core/src/emails/templates/addedContributionMessage/html.pug b/core/src/emails/templates/addedContributionMessage/html.pug new file mode 100644 index 000000000..df5ba35c4 --- /dev/null +++ b/core/src/emails/templates/addedContributionMessage/html.pug @@ -0,0 +1,16 @@ +extend ../layout.pug + +block content + h2= t('emails.addedContributionMessage.title') + .text-block + include ../includes/salutation.pug + p= t('emails.addedContributionMessage.commonGoodContributionMessage', { senderFirstName, senderLastName, contributionMemo }) + .content + h2= t('emails.addedContributionMessage.readMessage') + div(class="p_content") + p= t('emails.addedContributionMessage.message', { message }) + p= t('emails.addedContributionMessage.toSeeAndAnswerMessage') + + a.button-3(href=`${contributionFrontendLink}`) #{t('emails.general.toAccount')} + + include ../includes/doNotReply.pug diff --git a/core/src/emails/templates/addedContributionMessage/subject.pug b/core/src/emails/templates/addedContributionMessage/subject.pug new file mode 100644 index 000000000..4ac85fa23 --- /dev/null +++ b/core/src/emails/templates/addedContributionMessage/subject.pug @@ -0,0 +1 @@ += t('emails.addedContributionMessage.subject') diff --git a/core/src/emails/templates/contributionChangedByModerator/html.pug b/core/src/emails/templates/contributionChangedByModerator/html.pug new file mode 100644 index 000000000..46bcd4ae1 --- /dev/null +++ b/core/src/emails/templates/contributionChangedByModerator/html.pug @@ -0,0 +1,10 @@ +extend ../layout.pug + +block content + h2= t('emails.contributionChangedByModerator.title') + .text-block + include ../includes/salutation.pug + p= t('emails.contributionChangedByModerator.text', { contributionMemo, senderFirstName, senderLastName, contributionMemoUpdated }) + .content + include ../includes/contributionDetailsCTA.pug + include ../includes/doNotReply.pug \ No newline at end of file diff --git a/core/src/emails/templates/contributionChangedByModerator/subject.pug b/core/src/emails/templates/contributionChangedByModerator/subject.pug new file mode 100644 index 000000000..791cee555 --- /dev/null +++ b/core/src/emails/templates/contributionChangedByModerator/subject.pug @@ -0,0 +1 @@ += t('emails.contributionChangedByModerator.subject') diff --git a/core/src/emails/templates/contributionConfirmed/html.pug b/core/src/emails/templates/contributionConfirmed/html.pug new file mode 100644 index 000000000..310993d97 --- /dev/null +++ b/core/src/emails/templates/contributionConfirmed/html.pug @@ -0,0 +1,10 @@ +extend ../layout.pug + +block content + h2= t('emails.contributionConfirmed.title') + .text-block + include ../includes/salutation.pug + p= t('emails.contributionConfirmed.commonGoodContributionConfirmed', { contributionMemo, senderFirstName, senderLastName, amountGDD: contributionAmount }) + .content + include ../includes/contributionDetailsCTA.pug + include ../includes/doNotReply.pug \ No newline at end of file diff --git a/core/src/emails/templates/contributionConfirmed/subject.pug b/core/src/emails/templates/contributionConfirmed/subject.pug new file mode 100644 index 000000000..c5bd41421 --- /dev/null +++ b/core/src/emails/templates/contributionConfirmed/subject.pug @@ -0,0 +1 @@ += t('emails.contributionConfirmed.subject') diff --git a/core/src/emails/templates/contributionDeleted/html.pug b/core/src/emails/templates/contributionDeleted/html.pug new file mode 100644 index 000000000..daf54227d --- /dev/null +++ b/core/src/emails/templates/contributionDeleted/html.pug @@ -0,0 +1,10 @@ +extend ../layout.pug + +block content + h2= t('emails.contributionDeleted.title') + .text-block + include ../includes/salutation.pug + p= t('emails.contributionDeleted.commonGoodContributionDeleted', { contributionMemo, senderFirstName, senderLastName }) + .content + include ../includes/contributionDetailsCTA.pug + include ../includes/doNotReply.pug diff --git a/core/src/emails/templates/contributionDeleted/subject.pug b/core/src/emails/templates/contributionDeleted/subject.pug new file mode 100644 index 000000000..024588472 --- /dev/null +++ b/core/src/emails/templates/contributionDeleted/subject.pug @@ -0,0 +1 @@ += t('emails.contributionDeleted.subject') diff --git a/core/src/emails/templates/contributionDenied/html.pug b/core/src/emails/templates/contributionDenied/html.pug new file mode 100644 index 000000000..d30653acd --- /dev/null +++ b/core/src/emails/templates/contributionDenied/html.pug @@ -0,0 +1,10 @@ +extend ../layout.pug + +block content + h2= t('emails.contributionDenied.title') + .text-block + include ../includes/salutation.pug + p= t('emails.contributionDenied.commonGoodContributionDenied', { contributionMemo, senderFirstName, senderLastName }) + .content + include ../includes/contributionDetailsCTA.pug + include ../includes/doNotReply.pug diff --git a/core/src/emails/templates/contributionDenied/subject.pug b/core/src/emails/templates/contributionDenied/subject.pug new file mode 100644 index 000000000..57431e56e --- /dev/null +++ b/core/src/emails/templates/contributionDenied/subject.pug @@ -0,0 +1 @@ += t('emails.contributionDenied.subject') diff --git a/core/src/emails/templates/includes/Chatbox.svg b/core/src/emails/templates/includes/Chatbox.svg new file mode 100644 index 000000000..4eb68e0bb --- /dev/null +++ b/core/src/emails/templates/includes/Chatbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/core/src/emails/templates/includes/answear_button.svg b/core/src/emails/templates/includes/answear_button.svg new file mode 100644 index 000000000..f45fedc90 --- /dev/null +++ b/core/src/emails/templates/includes/answear_button.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + Jetzt antworten + + + diff --git a/core/src/emails/templates/includes/chatbox-icon.png b/core/src/emails/templates/includes/chatbox-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a25c7c209cb79912e5adab4b7732ca9858955e17 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9F5he4R}c>anMprB-l zYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt&fkT^vI^I^Rxpt*$!I@bcilmcXRrOkP_`0>HiiLiq(xj+>07kDqMfHY{##Q zlh#;pR2gl4c_ETL@xfeC%dqcrr^TpWs_@NqndEL~zIij>tP8)bE11vjc5$h#TT}z| O8-u5-pUXO@geCw$1$z7d literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/includes/chatbox-icon.pug b/core/src/emails/templates/includes/chatbox-icon.pug new file mode 100644 index 000000000..62775b0f0 --- /dev/null +++ b/core/src/emails/templates/includes/chatbox-icon.pug @@ -0,0 +1,6 @@ +span.chatbox-wrapper + img.bi-chatbox( + alt="chatbox" + loading="lazy" + src="cid:chatboxicon" + ) \ No newline at end of file diff --git a/core/src/emails/templates/includes/contributionDetailsCTA.pug b/core/src/emails/templates/includes/contributionDetailsCTA.pug new file mode 100644 index 000000000..ae3b77e6a --- /dev/null +++ b/core/src/emails/templates/includes/contributionDetailsCTA.pug @@ -0,0 +1,7 @@ +//- +h2= t('emails.general.contributionDetails') +div(class="p_content")= t('emails.contribution.toSeeContributionsAndMessages') +a.button-3(href=`${contributionFrontendLink}`) #{t('emails.general.toAccount')} +div(class="p_content")= t('emails.general.orCopyLink') + +a.clink(href=`${contributionFrontendLink}`) #{`${contributionFrontendLink}`} \ No newline at end of file diff --git a/core/src/emails/templates/includes/doNotReply.pug b/core/src/emails/templates/includes/doNotReply.pug new file mode 100644 index 000000000..506a5d0db --- /dev/null +++ b/core/src/emails/templates/includes/doNotReply.pug @@ -0,0 +1 @@ +div(class="p_content")= t('emails.general.pleaseDoNotReply') \ No newline at end of file diff --git a/core/src/emails/templates/includes/email.css b/core/src/emails/templates/includes/email.css new file mode 100644 index 000000000..5110c3882 --- /dev/null +++ b/core/src/emails/templates/includes/email.css @@ -0,0 +1,216 @@ +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 100; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 100; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 100; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 200; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 200; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 200; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 300; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 300; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 300; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 400; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 500; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 500; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 500; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 600; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 600; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 600; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 700; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 800; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 800; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 800; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* vietnamese */ +/* @font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 900; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} */ +/* latin-ext */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 900; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Work Sans'; + font-style: normal; + font-weight: 900; + src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/core/src/emails/templates/includes/facebook-icon.png b/core/src/emails/templates/includes/facebook-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1d880cf3e21f0eac022181f0540859e65c9d2635 GIT binary patch literal 1449 zcmV;a1y=frP)WmhDt1z%7D7m zQj!Z6h7TAE@2=H})G ztJUgd0AnOiq$Rf=08dEX&gb(tj~_q2l#0x)3YeXp9a>&q{!~P+kQ_?Erj`I$6p=}# z)P(Q*e{V@vrwvKM7&A)pnurW<#fUAi0N`p61a|D)Tqo_*hU7GW zQn6V4z1_BL2ViDq=3Ep-cS#;;x2;P6%zK`9sZc0Px6@9wQ`s0Z7DdthUUObVgyfMZ zitZa@#@cDOsQ{4lwAMGQwYNz2cV?n{NcLN6Z)vS>kn}dwrsWVI=^110lDxQe6SD)r zy&woK0f?H_YuN*gG1s@7^CBW7FB)U6x2o5)2N+|>P0`~LH!=f;>1NRC@; z-&9KNtIgWh+Sh^fPVWGWiO5$XaR9W|p{rx8b^Mm}z!+1s*4~Q^l=>edP3J{KNS@GI zhhZ4%+7KwEsv()bni%zdMmE$aiNtdN$qN}NT~2yH^0ka?sOh^PBBCml%3%PfvQ*v( zq}|V3>pNAcR1T~7rA4O7dx3b#e_oM1*==LG1<8{+lE+*K2k=FMvPVto|0smDSX1t5Myt$I2D0GtItDK*&Ei;*tjatMgB)~52B*&!~6z*0^rwd7(Ms! zi^b7K^^GxKlKiAWn|#`~)lf<;}yhgz@@VZEGUwhp3C(TB%dh& zPrGeMw*c@|0eIYPL%Ick#|prMPSZ=aGXMzSf%1L-1S9^n<%7RjAqP}2F08XDiy$IlHwl-x4 zfUE11t2Z2o1VM0zWLxQ`+X0f(K@i+oU%nwl1^~+%K6v_OK-_m)JHgAj=W5!5+)2kCBfR_NqTXp+2ZQ50`tFO$6y!v+_dA64p zOC+aBo^988k-ckkdlx77uFj?*WIem`@^litetrIbG9Al@qI{v(00000NkvXXu0mjf DhkUKj literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/includes/footer.pug b/core/src/emails/templates/includes/footer.pug new file mode 100644 index 000000000..91a0e4543 --- /dev/null +++ b/core/src/emails/templates/includes/footer.pug @@ -0,0 +1,77 @@ +footer + .w-container(class="footer_01") + .socialmedia + a.slink( + target="_blank" + href="https://www.facebook.com/groups/Gradido/" + ) + img.bi-facebook( + alt="facebook" + loading="lazy" + src="cid:facebookicon" + ) + a.slink( + target="_blank" + href="https://t.me/GradidoGruppe" + ) + img.bi-telegram( + alt="Telegram" + loading="lazy" + src="cid:telegramicon" + ) + a.slink( + target="_blank" + href="https://twitter.com/gradido" + ) + img.bi-twitter( + alt="Twitter" + loading="lazy" + src="cid:twittericon" + ) + a.slink( + target="_blank" + href="https://www.youtube.com/c/GradidoNet" + ) + img.bi-youtube( + alt="youtube" + loading="lazy" + src="cid:youtubeicon" + ) + .line + .footer + div(class="footer_p1")= t("emails.footer.contactOurSupport") + a( + class="footer_p2" + href='mailto:' + t("emails.footer.supportEmail") + )= t("emails.footer.supportEmail") + div + img.image( + alt="Gradido Logo" + src="https://gdd.gradido.net/img/brand/green.png" + ) + div + a( + class="terms_of_use" + href="https://gradido.net/de/impressum/" + target="_blank" + )= t("emails.footer.imprint") + br + a( + class="terms_of_use" + href="https://gradido.net/de/datenschutz/" + target="_blank" + )= t("emails.footer.privacyPolicy") + div(class="footer_p1") + | Gradido-Akademie + br + | Institut für Wirtschaftsbionik + br + | Pfarrweg 2 + br + | 74653 Künzelsau + br + | Deutschland + br + br + br + diff --git a/core/src/emails/templates/includes/gradido-header.jpeg b/core/src/emails/templates/includes/gradido-header.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..38a5c3a80f090b8973db6d603d406249f7af7f04 GIT binary patch literal 9427 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 literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/includes/greeting.pug b/core/src/emails/templates/includes/greeting.pug new file mode 100644 index 000000000..6693e23ca --- /dev/null +++ b/core/src/emails/templates/includes/greeting.pug @@ -0,0 +1,6 @@ +//- This sets the greeting at the end of every e-mail +.text-block + p + = t('emails.general.sincerelyYours') + br + = t('emails.general.yourGradidoTeam') \ No newline at end of file diff --git a/core/src/emails/templates/includes/header.pug b/core/src/emails/templates/includes/header.pug new file mode 100644 index 000000000..3160d3e2b --- /dev/null +++ b/core/src/emails/templates/includes/header.pug @@ -0,0 +1,13 @@ +header + .head + //- TODO + //- when https://gdd.gradido.net/img/gradido-email-header.jpg is on production, + //- replace this URL by https://gdd.gradido.net/img/brand/gradido-email-header.png + img.head-logo( + alt="Gradido Logo" + loading="lazy" + src="cid:gradidoheader" + ) + + + diff --git a/core/src/emails/templates/includes/requestNewLink.pug b/core/src/emails/templates/includes/requestNewLink.pug new file mode 100644 index 000000000..8baa3d6df --- /dev/null +++ b/core/src/emails/templates/includes/requestNewLink.pug @@ -0,0 +1,10 @@ +//- +requestNewLink + h2= t('emails.general.requestNewLink') + + if timeDurationObject.minutes == 0 + div(class="p_content")= t('emails.general.linkValidity', { hours: timeDurationObject.hours }) + else + div(class="p_content")= t('emails.general.linkValidityWithMinutes', { hours: timeDurationObject.hours, minutes: timeDurationObject.minutes }) + + a.button-4(href=resendLink) #{t('emails.general.newLink')} \ No newline at end of file diff --git a/core/src/emails/templates/includes/salutation.pug b/core/src/emails/templates/includes/salutation.pug new file mode 100644 index 000000000..3e2591951 --- /dev/null +++ b/core/src/emails/templates/includes/salutation.pug @@ -0,0 +1 @@ +p= t('emails.general.helloName', { firstName, lastName }) diff --git a/core/src/emails/templates/includes/telegram-icon.png b/core/src/emails/templates/includes/telegram-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4c36ff66148cb69d8c8f9373b33bca573c251ed8 GIT binary patch literal 2159 zcmV-#2$1)QP)bMFuniA}Vr(Ws3f zX=+J~xF)q|Qi+NFAht>4#}8A5HmO9usx}fq(cTEGv}W7Iq&=4^ZB0l5?w~ISX?6ME=fa@mXo|4z+&fI z))k{%kk(V>d{nC<*|qmvj%wRg&6jhomIEO!9dE zdx9W{($zFY2b?%@B0DxV_8`e&Nq3~hTMv@QCGGC-@87;+#fl55aCS;iDwP&pzI^#> z03MdKCtfU*0%61bZ&v>4o zDqCxZtJUg(`DQ!-NV>6Ftsbz}4kwXo$pMnQD2lc?=XOcDu00jI4@uWK=XOO=v_+EF zicHfXAjz}VJ}c?o&Q-j6Ai3Z7{dFX(bJc6w1FW@=zuSxl07>^+Yaee`Z_XZItsQpG z?MhFrs}Ez$mweyf-ROBk2gI}ef%!blvcpRgB-dJNH_Rxn|5GZJ7M088Q+Vh0 z_T9!g&+`WB4^UV1fcR85uZ<`90?98LV{#-nClp`ooZEB-U+u?<6DP9cX^4$H}e)h-ZN0TL7K|u*3KLgL8$l!Z7RsurZU#{3Vymy;T3KR4Uz6E|=Th ztVy~D05Zj5afx$osN3V8Q)em60^m2~h)B06PZ;27cZ^`B@Q$;ioQMyts|zG626E7#R5c;Naj}v(=TTr#7hqwkxTn0SAC8ov#aw`Ty{ zkW^688^)Mt;;rfNb{ej)TaZS<&thJx4R4SvAHq{#sV06KP1s_goe6d(u z0^p{kddvpr+=YxW=7OZA6QQIv)oS&nD2iSMun)lAAP7oxDe9bi!a4WAELeZ{yCsjJtw{Oga41jY0KA1p(+W>3^u=()e!zW4Z%VaWpbGh7Ttxgz*U#M2AKLqgJ z>GCA^FI~FybIX=3n`l$-)EofdTt?C<0EKp>NiGNQNTpJFB#NTr0QLg7OVZs9M0WbV z|4@SC?hK@{1FYjZl_7aDjU^?HCp-qAk#XNH6bg@a+)#==faFO-ay{O;nJl`sdaynB6-N<^ZB!qUQUtN)E{C< zo*o(+`gf^R>Wu>&Z6oFJ|8hQ`KWhLW&cjQKn7VROISl}J-g)OZFcsx#3(mPT$N%%d z+fm^?0KT3U`7}&jNEQl(%dvyZTu0qGkXjGGq|K8zLqQNkB-=XG%?3`Q)(cKgdnRjb zJ`BSjg<-g`RnB6ucs+nyQ_}BvE$g&?VtP6aasZHIB)Pb;D;!|0y<5^j02?L!wNxs# z6p(Swr8)km4s}xw=;)fJm25n zzrFT<$^r3R*^_BBQrDPzdU{?50Bh|-B!4kW#z_{yz9@>eG?^gNngE}y&ojPaZSLvm zc>7Nx}umvm_tzegBWOvM>x6$7wDdh3`oY2SISfTsMPI62mb3^E;U(5-*XDEnK+p zsqyjg>q%~_-Q=_jNh5_q;Um*`z1NbYW)mnB3a35KTSv0oef7GFI8AO{qfGLKlTt31 z8zH%|d#YU>klZ*|2Kk&PG~f4kliWI2o%sxsTbo6)uO&;jKva#1-ZecTe)CO@2NHfU zVyzvPv~9lT50fmD+?eD7=h`PTNgK-LawC$~NJ`XDHz8?6(wd~k1J^#AyY}JawNGc$ lAeoN;%a5lUVZMJp|6hafLt8=zP{RNK002ovPDHLkV1k2FAsYYy literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/includes/twitter-icon.png b/core/src/emails/templates/includes/twitter-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fffb9b59939b564a552879830d1244e319c9ba8e GIT binary patch literal 2002 zcmV;@2QB!CP)2v^jL`{t)V1_VYpM$PXVmRA|eAWko=M7c?U=;4MC~~@O}SQ zNry;oNn@WkBpoBUqg*b(o76UO0~|kod`le1uSmK%scj=c@_eCC*xuFEbu5XUNm4ir z!|phak1RIl0YK8taU35B!>~Jv-Mkt=QXvR}mz;BZCAFlJ*my{4an9`xg5V`dh56Xj z{RAWx!Z3VA(zfgp7Y-zU?|I&KlJQ*S>h^#z3}5`PIS&AmwuNE%V!d*6_JA-9yPb1; z^OLpkFvdLQdEUO+exJ1gs-yjp#r)0B2PDS|g~GkF%?>j*fbaXal6-41j`nFl^1P(Y zGp!S*jRBG<>CpA!JaA=-tok(VA3m)C!Z6&qSXOv>g5;Jk40ld@U;9w0RF;p8jh(>< zx3+IIE))ud&(&_AuId5RUETHSJaFY8=KHlTrg}hMUtj0Q$jCbjwWY0tnB*XUk4ajR zCo##39UUFFO`a!A^?;F)k?(wv&P$pgxu;MlY_ZlZvDV&Vt!*{N+)478>KVWkNM0tn z2f*tI>sdZLJpB0NbL}UPXcJK*L;xNlc{q)I6@PDOX(?H2pD2||f301YeNl6qoe(4dM?SbwKkaS0S_l7s3H0-0IXWI>VIu*ZQDq`k;L8@ z^KcsH0bq1=^z#6|LGsrr%y$6QPe9U_(g*+ml7E~0yI3p^d!F}Y06!t==3)N2wf4=l zbz5uy(9zNHmUHf|q_&c_0)UC4XeG(@X+;1St$iTr%H{IY0JZ`+F_)n+=64zD1pthU zj2s}jCaE3C^-&b9G}WL*>cdgzTyduN*4iW1+Ad?vBLL3KV&0RsUf=hdgCO{or0r?! zt4scSnk3EWzfP(-IhGAHC&V7^Qea^YnB%7Rb7iY7bN4+mg`g&S>0FYEP zk`i~HS~%x+Mp3k~UOCV6{BpVcLu+lZy}i8yz{a+=wp4>307$ZFZEHBzG?82*r8-gv z0FZp8+70*2*QQu3j-k%@P!Ezi$ZT;PlB=5l+?0W1-1EH0(gr2cqIyWXEC;F;#yQuS zfuQ-si4&j7K}aI>^z_^TpgAi~H9~E&GyolD#?c6-e&y?d@$yBq<1j2PEB}Cnw2X zL-J@|D>+GbU%q_#U{6m^M;?5Ws8lMScFrBhlar)K9yO&>X+YA+yojB14~>tHhfx%L zRZ>${zW)CHC1Yb_zag1r$vzE|PL@ig0RsTlJiI)y+BtV1ilRreko5QWFBuvddKJJI za?&-0NuMVNltVd@UL<+g81wCA%a+~dd0y(!dT(#<(xIWDS0&w-hqf7T2&f5+1VPZ7 zB*Bs7JI0u;aU8ccH8r`3iHY~EweRIIoH_p!OTx58#Ca zJfCsSJ=)yd{QRa(n?~{w*3;9|F)=am1LxdR0CJ58)k4x#!bIlKn56fNF+Xo_Z{M?S z-MYavf}$w;cpS%%0C)<(EonIBi)%w;R~@MYLGY}kXVMT$`mZtOu%y>oT3Y_HapT5+ z%vHWpsoWmN@mW=_SvcDYeeN49)F)?ucSc${~=kBw4CH8s)wSv zPHXeTwD9<}L$x3XzE%5;Tu&g`ZLQsZ)w^p8NuuxjZ(eU%B9e}k%jLVTou#I2EUHVy z9VE{$oV><@N-YpSL38D z3`p*pD}#K_y|w3g`$+E2U)I8ahzpWd^u1J4o6rDN#j@grsAVHYar+xN&Xn#>L4SS7-Ae kxfUPE%hR)Av0tD6KRO$}cDgFm=l}o!07*qoM6N<$f{G#L5&!@I literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/includes/webflow.css b/core/src/emails/templates/includes/webflow.css new file mode 100644 index 000000000..45e4420c4 --- /dev/null +++ b/core/src/emails/templates/includes/webflow.css @@ -0,0 +1,166 @@ +body{ + display: block; + font-family: "Work Sans", sans-serif; + font-size: 17px; + text-align: center; + text-align: -webkit-center; + justify-content: center; + padding: 0px; + margin: 0px; +} + +h2 { + margin-top: 15px; + color: #383838; +} + +.container { + max-width: 680px; + margin: 0 auto; + display: block; +} + +.head-logo { + width: 100%; + height: auto; +} + +.text-block { + margin-top: 20px; + color: #9ca0a8; +} + +.content { + display: block; + width: 78%; + margin: 40px 1% 40px 1%; + padding: 20px 10% 40px 10%; + border-radius: 24px; + background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5); +} + +.p_content{ + margin: 15px 0 15px 0; + line-height: 26px; + color: #696c72; +} + +.clink { + line-break: anywhere; + margin-bottom: 40px; +} + +.button-3, +.button-4, +.button-5 { + display: inline-block; + padding: 9px 15px; + color: white; + border: 0; + line-height: inherit; + text-decoration: none; + cursor: pointer; + border-radius: 20px; + background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); + box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); + margin: 25px 0 25px 0; + width: 50%; +} + +.button-4 { + background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2); +} + +.button-5 { + background: linear-gradient(135deg, #53900c, #6e6e6e); + font-size: 20px; + font-weight: 600; + color: #f5f5f5; + width: auto; + box-shadow: 20px 20px 25px; + transition: all 0.3s ease; +} + +.button-5:hover { + transform: translateY(-5px); + box-shadow: 20px 25px 30px rgba(56, 56, 56, 0.4); +} + +.chatbox-wrapper { + margin-right: 8px; +} +.bi-chatbox { + margin-bottom: -5px; +} + +.child-right { + text-align: right; +} +.child-left { + text-align: left; +} + +.socialmedia { + display: flex; + margin-top: 40px; + max-width: 600px; + +} +.slink{ + width: 150px; +} + +.footer { + padding-bottom: 20px; +} + +.footer_p1 { + margin-top: 30px; + color: #9ca0a8; + margin-bottom: 30px; +} + +.footer_p2 { + color: #383838; + font-weight: bold; +} + + +.image { + width: 200px; + margin-top: 30px; + margin-bottom: 30px; +} + +.div-block { + display: table; + margin-top: 20px; + margin-bottom: 40px; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.terms_of_use { + color: #9ca0a8; +} + +.text-block-3 { + color: #9ca0a8; + margin-bottom: 30px; +} + +.line_image, +.line { + width: 100%; + height: 13px; + margin-top: 40px; +} + +.line_image { + background-image: linear-gradient(90deg, #c58d38, #c58d38 0%, #f3cd7c 35%, #dbb056 54%, #eec05f 63%, #cc9d3d); +} + +.line { + background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d); +} diff --git a/core/src/emails/templates/includes/youtube-icon.png b/core/src/emails/templates/includes/youtube-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d135ba625d2749adad59d87623b082797418f5ca GIT binary patch literal 1802 zcmV+l2le=gP)A6O75=_ElNjVNA;O7-5TOgwnA%F_y_qafL{%!fVbMi4 zNR|-6MXj=dt|DavsEewq3JqC+h?I~8@`6PdEXo4mNTPBc>FVd_svY4G~Z@4@4fGwbI-f)-h0kHm*_I8)#?FB&q^AWbcE#700y0N z1ICyE0C3JN8Do|J%uAXfd7I=7l2?KtxZ6$p*bSjk6qNvsN_v6hh$JsPBqixO$v*=a zFO^DBXD#iZ1E!~^2bPzYUnV&w>6uQ+Z3fAkk}eerg$qMNLrWcznN>ioR@=Y2y806U zKbEw=12(k<$$J3K8)MD|L9mcXmM>8ft+l5ly$N72ixC+xPx4F{hL=goM}U_DDwWD1 zN#i6>`0zUoNs}Z;%jNP1X}PH#aP{id6LB2BBk5pTZZ|=4E|<%lEEbECX?P~h!`9ld zIF2WFTjK#h(!n^6C# zhcV`*Fbpqkb$?3-B%}SrZvN(X0+K7aT<-a;W`|83P^nZ7k^IMQ9PNETa!%6m&DIGU z#sEo_H2%0W9$1?qlQwO5;Ts%atv$6{R(PER$rIMvQyZ=~|Ebk#`&U+0X7KRV_T9#O zE|)vp96+t>0ZCN%xHcYGOT@g|eBnV4n4X>`h?_tl1`G78c%g(vyCA}u; zDIYl`$B;OHz*-JZQpHo)ElJ-jm&=Pjd|%AY&VFHWaq)cs!#;eHHM-NNuOY^m zAN9KN0C4#5;s56I`Bb5A3r2xt7LfFUj|7r;f*^Q5gAtifEEfMx@}EB3Mw|21YW09~ zZbb4*sa;F+u(kFWfbSV&E*Fc%86SnMkaQiu*VFPyj#R7F118zD@Xg!bPV>B^UpnW` z#&KMWqUdL{v$K6ZdRuIm_2DH;{%4IOuR#O=oOAz5skA@&?UVHLg@uKwYPI^Dul_{V zzcX-$jie*K0!V)B%T4%4;y8ZKTKl_Ow{CsOQ_Q@teo03R$t(`&$nK1D?o_>ApRQCY zKS;|p#w`2lCHb@g;OlviT=nH{fR;%s!rDU{W&^YG?eA&*qj<5J6J-52L zIu%9H*>2mA>`)tT2gq~o+=1LaNv~hKcI~U(w80oNkSVYr*_G|}ME37TMn*pDwhhKP z=RJ^h!vQ4k7-PO$DwV#!lb|Y#4M|~!$ug4f$-rF)N%u*u?>$s4{7NGiT|3}eh2aU6eajJc5VJKqjN zzC@BY@+7Y$)mW)VQ%R|m2SM;IfOpgCX@hV0kVuN;6%z!(-6WwW(wAPN7n% z4Ea{1NxB{c!CeCYNgbXSB>iTm#R#25qVw0j{6?D_E5Y#$hJ43b`6aY8+_V7>T0jrX;WLsR@fDKLjw>*cXtrO!9w{R!DwA@_u7az!>8Iz&U4{ z_6G8j`bh4T^m&qnrhS2flD-09Ult=t-Yk_$!$8x%fTW86+E!Gw!9Gd*06de(MC)(! zjME&*wcgu|+bKwTP%!Zz7%CJB7m^Ch#~LK>6$*t5jsFiEknEM6e<)V<7U!GmjMs(3 zd-m-46*A=59s$f7W6m{SSm%JFM~~hkd8W5E^$sM@v=&!yn6@ObQmOp)ajO!MG+8c} zztvh)y&)r%ED=XZ&h^f`?ta=H9LE|)t=a;5v`br(sQ+{vvf$+yf2 z7K_D6lBc_8T5mw|^mY~G+a^WBFuX+a+;-3GW{^C$U6m;Cq*%Iru{6mz5%kFPgyhY) zZ9I_j#E7+aED3*iW&JS86_Tghb^CRkv`RkHM`nPv*+J5ANvRZd6Otw+9Z%bM;K{MM sCkH2=9G&fikXC#q4^MA}-F|%jQ$FLp<@n27i2wiq07*qoM6N<$f^Fe$FaQ7m literal 0 HcmV?d00001 diff --git a/core/src/emails/templates/layout.pug b/core/src/emails/templates/layout.pug new file mode 100644 index 000000000..0995b2647 --- /dev/null +++ b/core/src/emails/templates/layout.pug @@ -0,0 +1,26 @@ +doctype html +html(lang=locale) + head + meta( + content="multipart/html; charset=UTF-8" + http-equiv="content-type" + ) + meta( + name="viewport" + content="width=device-width, initial-scale=1" + ) + style. + .wf-force-outline-none[tabindex="-1"]:focus{outline:none;} + style + include includes/email.css + include includes/webflow.css + + body + div.container + include includes/header.pug + + .wrapper + block content + include includes/greeting.pug + + include includes/footer.pug diff --git a/core/src/emails/templates/resetPassword/html.pug b/core/src/emails/templates/resetPassword/html.pug new file mode 100644 index 000000000..4d4ed3f50 --- /dev/null +++ b/core/src/emails/templates/resetPassword/html.pug @@ -0,0 +1,16 @@ +extends ../layout.pug + +block content + h2= t('emails.resetPassword.title') + .text-block + include ../includes/salutation.pug + p= t('emails.resetPassword.youOrSomeoneResetPassword') + .content + h2= t('emails.resetPassword.title') + div(class="p_content")= t('emails.resetPassword.pleaseClickLink') + a.button-3(href=resetLink) #{t('emails.general.reset')} + div(class="p_content")= t('emails.general.orCopyLink') + + a.clink(href=resetLink) #{resetLink} + + include ../includes/requestNewLink.pug diff --git a/core/src/emails/templates/resetPassword/subject.pug b/core/src/emails/templates/resetPassword/subject.pug new file mode 100644 index 000000000..21f277316 --- /dev/null +++ b/core/src/emails/templates/resetPassword/subject.pug @@ -0,0 +1 @@ += t('emails.resetPassword.subject') diff --git a/core/src/emails/templates/transactionLinkRedeemed/html.pug b/core/src/emails/templates/transactionLinkRedeemed/html.pug new file mode 100644 index 000000000..281ee9205 --- /dev/null +++ b/core/src/emails/templates/transactionLinkRedeemed/html.pug @@ -0,0 +1,18 @@ +extend ../layout.pug + +block content + h2= t('emails.transactionLinkRedeemed.title', { senderFirstName, senderLastName }) + .text-block + include ../includes/salutation.pug + p= t('emails.transactionLinkRedeemed.hasRedeemedYourLink', { senderFirstName, senderLastName, senderEmail }) + .content + h2= t('emails.general.transactionDetails') + div(class="p_content")= t('emails.general.amountGDD', { amountGDD: transactionAmount }) + br + = t('emails.transactionLinkRedeemed.memo', { transactionMemo }) + br + = t('emails.general.detailsYouFindOnLinkToYourAccount') + + a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} + + include ../includes/doNotReply.pug diff --git a/core/src/emails/templates/transactionLinkRedeemed/subject.pug b/core/src/emails/templates/transactionLinkRedeemed/subject.pug new file mode 100644 index 000000000..9070b60b3 --- /dev/null +++ b/core/src/emails/templates/transactionLinkRedeemed/subject.pug @@ -0,0 +1 @@ += t('emails.transactionLinkRedeemed.subject', { senderFirstName, senderLastName }) diff --git a/core/src/emails/templates/transactionReceived/html.pug b/core/src/emails/templates/transactionReceived/html.pug new file mode 100644 index 000000000..4f9aa9c31 --- /dev/null +++ b/core/src/emails/templates/transactionReceived/html.pug @@ -0,0 +1,30 @@ +extend ../layout.pug + +block content + mixin mailto(email, subject) + - var formattedSubject = encodeURIComponent(subject) + a(class!=attributes.class href=`mailto:${email}?subject=${formattedSubject}`) + block + + - var subject= t('emails.transactionReceived.replySubject', { senderFirstName, senderLastName, transactionAmount }) + h2= t('emails.transactionReceived.title', { senderFirstName, senderLastName, transactionAmount }) + .text-block + include ../includes/salutation.pug + p + = t('emails.transactionReceived.haveReceivedAmountGDDFrom', { transactionAmount, senderFirstName, senderLastName }) + | ( + +mailto(senderEmail, subject)=senderEmail + |). + .content + h2= t('emails.general.message') + .child-left + div(class="p_content")= memo + .child-right + +mailto(senderEmail, subject)(class="button-5") + include ../includes/chatbox-icon.pug + span #{t('emails.general.answerNow')} + + a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} + + + diff --git a/core/src/emails/templates/transactionReceived/subject.pug b/core/src/emails/templates/transactionReceived/subject.pug new file mode 100644 index 000000000..872806ebc --- /dev/null +++ b/core/src/emails/templates/transactionReceived/subject.pug @@ -0,0 +1 @@ += t('emails.transactionReceived.subject', { senderFirstName, senderLastName, transactionAmount }) diff --git a/core/src/index.ts b/core/src/index.ts index a10eb6caa..a429bdc3b 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -18,6 +18,7 @@ export * from './graphql/logic/settlePendingSenderTransaction' export * from './graphql/logic/storeForeignUser' export * from './graphql/model/Decay' export * from './graphql/model/EncryptedTransferArgs' +export * from './emails' export * from './util/calculateSenderBalance' export * from './util/utilities' export * from './validation/user' diff --git a/core/src/types/images.d.ts b/core/src/types/images.d.ts new file mode 100644 index 000000000..ef7006d32 --- /dev/null +++ b/core/src/types/images.d.ts @@ -0,0 +1,14 @@ +declare module '*.jpg' { + const value: string + export default value +} +declare module '*.jpeg' { + const value: string + export default value +} +declare module '*.png' { + const value: string + export default value +} + + \ No newline at end of file diff --git a/core/src/validation/user.test.ts b/core/src/validation/user.test.ts index cd3bd1925..fb9cf7b94 100644 --- a/core/src/validation/user.test.ts +++ b/core/src/validation/user.test.ts @@ -1,22 +1,31 @@ import { validateAlias } from './user' import { getLogger } from '../../../config-schema/test/testSetup.bun' -import { describe, it, expect, beforeEach, mock, jest } from 'bun:test' -import { aliasExists } from 'database' +import { describe, it, expect, mock, jest, afterAll, beforeEach } from 'bun:test' import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const' +import { aliasExists, AbstractLoggingView, AppDatabase } from 'database' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.validation.user`) -mock.module('database', () => ({ - aliasExists: jest.fn(), -})) mock.module('shared/src/schema/user.schema', () => ({ aliasSchema: { parse: jest.fn(), }, })) -describe('validate alias', () => { - beforeEach(() => { +// bun mock module currently cannot be restored, so we must mock compatible with all tests! +mock.module('database', () => ({ + aliasExists: jest.fn(), + AbstractLoggingView, + AppDatabase, +})) + + +afterAll(() => { + mock.restore() +}) + +describe('validate alias', () => { + beforeEach(() => { jest.clearAllMocks() }) @@ -52,7 +61,7 @@ describe('validate alias', () => { describe('test against existing alias in database', () => { describe('alias exists in database', () => { it('throws and logs an error', () => { - (aliasExists as jest.Mock).mockResolvedValue(true) + (aliasExists as jest.Mock).mockReturnValue(true) expect(validateAlias('b-b')).rejects.toEqual(new Error('Given alias is already in use')) expect(logger.warn.mock.calls[0]).toEqual(['alias already in use', 'b-b']) }) @@ -60,7 +69,7 @@ describe('validate alias', () => { describe('valid alias', () => { it('resolves to true', async () => { - (aliasExists as jest.Mock).mockResolvedValue(false) + (aliasExists as jest.Mock).mockReturnValue(false) expect(validateAlias('bibi')).resolves.toEqual(true) }) }) diff --git a/core/tsconfig.json b/core/tsconfig.json index f4fef84fa..155a31a7b 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -5,6 +5,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "resolveJsonModule": true, // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ @@ -69,6 +70,10 @@ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, + "include": [ + "src/**/*.ts", + "src/**/*.json", + ], "references": [], /* Any project that is referenced must itself have a `references` array (which may be empty). */ - "exclude": ["**/*.test.ts", "**/*.spec.ts", "test/*", "**/bun.d.ts"], + "exclude": ["**/*.test.ts", "**/*.spec.ts", "test/*", "**/bun.d.ts", "esbuild.config.ts"], } From 9d4bda53dabf8f8bc72400f0a71e1a296a6f98ed Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:42:56 +0100 Subject: [PATCH 138/226] remove email from backend --- backend/src/emails/README.md | 50 - .../sendEmailVariants.test.ts.snap | 1736 ----------------- .../src/emails/sendEmailTranslated.test.ts | 149 -- backend/src/emails/sendEmailTranslated.ts | 118 -- backend/src/emails/sendEmailVariants.test.ts | 623 ------ backend/src/emails/sendEmailVariants.ts | 225 --- .../templates/accountActivation/html.pug | 18 - .../templates/accountActivation/subject.pug | 1 - .../accountMultiRegistration/html.pug | 22 - .../accountMultiRegistration/subject.pug | 1 - .../addedContributionMessage/html.pug | 16 - .../addedContributionMessage/subject.pug | 1 - .../contributionChangedByModerator/html.pug | 10 - .../subject.pug | 1 - .../templates/contributionConfirmed/html.pug | 10 - .../contributionConfirmed/subject.pug | 1 - .../templates/contributionDeleted/html.pug | 10 - .../templates/contributionDeleted/subject.pug | 1 - .../templates/contributionDenied/html.pug | 10 - .../templates/contributionDenied/subject.pug | 1 - .../src/emails/templates/includes/Chatbox.svg | 1 - .../templates/includes/answear_button.svg | 22 - .../templates/includes/chatbox-icon.png | Bin 323 -> 0 bytes .../templates/includes/chatbox-icon.pug | 6 - .../includes/contributionDetailsCTA.pug | 7 - .../emails/templates/includes/doNotReply.pug | 1 - .../src/emails/templates/includes/email.css | 216 -- .../templates/includes/facebook-icon.png | Bin 1449 -> 0 bytes .../src/emails/templates/includes/footer.pug | 77 - .../templates/includes/gradido-header.jpeg | Bin 9427 -> 0 bytes .../emails/templates/includes/greeting.pug | 6 - .../src/emails/templates/includes/header.pug | 13 - .../templates/includes/requestNewLink.pug | 10 - .../emails/templates/includes/salutation.pug | 1 - .../templates/includes/telegram-icon.png | Bin 2159 -> 0 bytes .../templates/includes/twitter-icon.png | Bin 2002 -> 0 bytes .../src/emails/templates/includes/webflow.css | 166 -- .../templates/includes/youtube-icon.png | Bin 1802 -> 0 bytes backend/src/emails/templates/layout.pug | 26 - .../emails/templates/resetPassword/html.pug | 16 - .../templates/resetPassword/subject.pug | 1 - .../transactionLinkRedeemed/html.pug | 18 - .../transactionLinkRedeemed/subject.pug | 1 - .../templates/transactionReceived/html.pug | 30 - .../templates/transactionReceived/subject.pug | 1 - 45 files changed, 3623 deletions(-) delete mode 100644 backend/src/emails/README.md delete mode 100644 backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap delete mode 100644 backend/src/emails/sendEmailTranslated.test.ts delete mode 100644 backend/src/emails/sendEmailTranslated.ts delete mode 100644 backend/src/emails/sendEmailVariants.test.ts delete mode 100644 backend/src/emails/sendEmailVariants.ts delete mode 100644 backend/src/emails/templates/accountActivation/html.pug delete mode 100644 backend/src/emails/templates/accountActivation/subject.pug delete mode 100644 backend/src/emails/templates/accountMultiRegistration/html.pug delete mode 100644 backend/src/emails/templates/accountMultiRegistration/subject.pug delete mode 100644 backend/src/emails/templates/addedContributionMessage/html.pug delete mode 100644 backend/src/emails/templates/addedContributionMessage/subject.pug delete mode 100644 backend/src/emails/templates/contributionChangedByModerator/html.pug delete mode 100644 backend/src/emails/templates/contributionChangedByModerator/subject.pug delete mode 100644 backend/src/emails/templates/contributionConfirmed/html.pug delete mode 100644 backend/src/emails/templates/contributionConfirmed/subject.pug delete mode 100644 backend/src/emails/templates/contributionDeleted/html.pug delete mode 100644 backend/src/emails/templates/contributionDeleted/subject.pug delete mode 100644 backend/src/emails/templates/contributionDenied/html.pug delete mode 100644 backend/src/emails/templates/contributionDenied/subject.pug delete mode 100644 backend/src/emails/templates/includes/Chatbox.svg delete mode 100644 backend/src/emails/templates/includes/answear_button.svg delete mode 100644 backend/src/emails/templates/includes/chatbox-icon.png delete mode 100644 backend/src/emails/templates/includes/chatbox-icon.pug delete mode 100644 backend/src/emails/templates/includes/contributionDetailsCTA.pug delete mode 100644 backend/src/emails/templates/includes/doNotReply.pug delete mode 100644 backend/src/emails/templates/includes/email.css delete mode 100644 backend/src/emails/templates/includes/facebook-icon.png delete mode 100644 backend/src/emails/templates/includes/footer.pug delete mode 100644 backend/src/emails/templates/includes/gradido-header.jpeg delete mode 100644 backend/src/emails/templates/includes/greeting.pug delete mode 100644 backend/src/emails/templates/includes/header.pug delete mode 100644 backend/src/emails/templates/includes/requestNewLink.pug delete mode 100644 backend/src/emails/templates/includes/salutation.pug delete mode 100644 backend/src/emails/templates/includes/telegram-icon.png delete mode 100644 backend/src/emails/templates/includes/twitter-icon.png delete mode 100644 backend/src/emails/templates/includes/webflow.css delete mode 100644 backend/src/emails/templates/includes/youtube-icon.png delete mode 100644 backend/src/emails/templates/layout.pug delete mode 100644 backend/src/emails/templates/resetPassword/html.pug delete mode 100644 backend/src/emails/templates/resetPassword/subject.pug delete mode 100644 backend/src/emails/templates/transactionLinkRedeemed/html.pug delete mode 100644 backend/src/emails/templates/transactionLinkRedeemed/subject.pug delete mode 100644 backend/src/emails/templates/transactionReceived/html.pug delete mode 100644 backend/src/emails/templates/transactionReceived/subject.pug diff --git a/backend/src/emails/README.md b/backend/src/emails/README.md deleted file mode 100644 index 9ab1d1124..000000000 --- a/backend/src/emails/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Using `forwardemail`–`email-templates` With `pug` Package - -You'll find the GitHub repository of the `email-templates` package and the `pug` package here: - -- [email-templates](https://github.com/forwardemail/email-templates) -- [pug](https://www.npmjs.com/package/pug) - -## `pug` Documentation - -The full `pug` documentation you'll find here: - -- [pugjs.org](https://pugjs.org/) - -### Caching Possibility - -In case we are sending many emails in the future there is the possibility to cache the `pug` templates: - -- [cache-pug-templates](https://github.com/ladjs/cache-pug-templates) - -## Testing - -To test your send emails you have different possibilities: - -### In General - -To send emails to yourself while developing set in `.env` the value `EMAIL_TEST_MODUS=true` and `EMAIL_TEST_RECEIVER` to your preferred email address. - -### Unit Or Integration Tests - -To change the behavior to show previews etc. you have the following options to be set in `sendEmailTranslated.ts` on creating the email object: - -```js - const email = new Email({ - … - // send emails in development/test env: - send: true, - … - // to open send emails in the browser - preview: true, - // or - // to open send emails in a specific the browser - preview: { - open: { - app: 'firefox', - wait: false, - }, - }, - … - }) -``` diff --git a/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap b/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap deleted file mode 100644 index aec3510fe..000000000 --- a/backend/src/emails/__snapshots__/sendEmailVariants.test.ts.snap +++ /dev/null @@ -1,1736 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`sendEmailVariants sendAccountActivationEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Email Verification

-
-

Hello Peter Lustig,

-

Your email address has just been registered with Gradido.

-
-
-

Complete registration

-
Please click here to complete the registration and activate your Gradido account.
Activate account -
Or copy the link into your browser window.
http://localhost/checkEmail/6627633878930542284 - -

Request new valid link

-
The link has a validity of 23 hours and 30 minutes. -If the validity of the link has already expired, you can have a new link sent to you here.
New link -
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendAccountMultiRegistrationEmail calls "sendEmailTranslated" result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Try To Register Again With Your Email

-
-

Hello Peter Lustig,

-

Your email address has just been used again to register an account with Gradido.
However, an account already exists for your email address. -

-
-
-

Reset password

-
If you have forgotten your password, please click here.
reset -
Or copy the link into your browser window.
http://localhost/forgot-password -

Contact support

-
If you did not try to register again, please contact our support:
support@supportmail.com -
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendAddedContributionMessageEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Message about your common good contribution

-
-

Hello Peter Lustig,

-

You have received a message from Bibi Bloxberg regarding your common good contribution “My contribution.”.

-
-
-

Read and reply to message

-
-

„My message.“

-

To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.

-
To account -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendContributionChangedByModeratorEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Your common good contribution has been changed

-
-

Hello Peter Lustig,

-

your common good contribution 'My contribution.' has just been changed by Bibi Bloxberg and now reads as 'This is a better contribution memo.'

-
-
-

Contribution details

-
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account -
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendContributionConfirmedEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Your contribution to the common good was confirmed

-
-

Hello Peter Lustig,

-

Your common good contribution “My contribution.” has just been approved by Bibi Bloxberg. Your Gradido account has been credited with 23.54 GDD.

-
-
-

Contribution details

-
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account -
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendContributionDeletedEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Your common good contribution was deleted

-
-

Hello Peter Lustig,

-

Your common good contribution “My contribution.” was deleted by Bibi Bloxberg.

-
-
-

Contribution details

-
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account -
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendContributionDeniedEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Your common good contribution was rejected

-
-

Hello Peter Lustig,

-

Your common good contribution “My contribution.” was rejected by Bibi Bloxberg.

-
-
-

Contribution details

-
To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab.
To account -
Or copy the link into your browser window.
https://gradido.net/contributions/own-contributions/1#contributionListItem-1 -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendResetPasswordEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Reset password

-
-

Hello Peter Lustig,

-

You, or someone else, requested a password reset for this account.

-
-
-

Reset password

-
If it was you, please click here.
reset -
Or copy the link into your browser window.
http://localhost/reset-password/3762660021544901417 - -

Request new valid link

-
The link has a validity of 23 hours and 30 minutes. -If the validity of the link has already expired, you can have a new link sent to you here.
New link -
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendTransactionLinkRedeemedEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Bibi Bloxberg has redeemed your Gradido link

-
-

Hello Peter Lustig,

-

Bibi Bloxberg (bibi@bloxberg.de) has just redeemed your link.

-
-
-

Transaction details

-
Amount: 17.65 GDD
Message: You deserve it! 🙏🏼
You can find transaction details in your Gradido account. -
To account -
Please do not reply to this email.
-
-
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; - -exports[`sendEmailVariants sendTransactionReceivedEmail result has the correct html as snapshot 1`] = ` -" - - - - - - - - -
-
-
\\"Gradido
-
-
-

Bibi Bloxberg has sent you 37.40 Gradido

-
-

Hello Peter Lustig,

-

You have just received 37.40 GDD from Bibi Bloxberg (bibi@bloxberg.de). -

-
-
-

Message

-
-
Du bist schon lustiger ;)
-
- -
To account -
-

Kind regards,
your Gradido team -

-
-
-
-
-
\\"facebook\\"\\"Telegram\\"\\"Twitter\\"\\"youtube\\"
-
-
-
If you have any further questions, please contact our support.
support@gradido.net -
\\"Gradido
-
Privacy Policy -
Gradido-Akademie
Institut für Wirtschaftsbionik
Pfarrweg 2
74653 Künzelsau
Deutschland


-
-
-
-
- -" -`; diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts deleted file mode 100644 index 103296080..000000000 --- a/backend/src/emails/sendEmailTranslated.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { createTransport } from 'nodemailer' - -import { i18n } from '@test/testSetup' - -import { CONFIG } from '@/config' - -import { getLogger } from 'config-schema/test/testSetup' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -import { sendEmailTranslated } from './sendEmailTranslated' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`) - -const testMailServerHost = 'localhost' -const testMailServerPort = 1025 - -CONFIG.EMAIL = false -CONFIG.EMAIL_SMTP_HOST = testMailServerHost -CONFIG.EMAIL_SMTP_PORT = testMailServerPort -CONFIG.EMAIL_SENDER = 'info@gradido.net' -CONFIG.EMAIL_USERNAME = 'user' -CONFIG.EMAIL_PASSWORD = 'pwd' -CONFIG.EMAIL_TLS = true - -jest.mock('nodemailer', () => { - return { - __esModule: true, - createTransport: jest.fn(() => { - return { - sendMail: () => { - return { - messageId: 'message', - } - }, - } - }), - } -}) - -describe('sendEmailTranslated', () => { - let result: Record | boolean | null - - describe('config email is false', () => { - beforeEach(async () => { - result = await sendEmailTranslated({ - receiver: { - to: 'receiver@mail.org', - cc: 'support@gradido.net', - }, - template: 'accountMultiRegistration', - locals: { - locale: 'en', - }, - }) - }) - - it('logs warning', () => { - expect(logger.info).toBeCalledWith('Emails are disabled via config...') - }) - - it('returns false', () => { - expect(result).toBeFalsy() - }) - }) - - describe('config email is true', () => { - beforeEach(async () => { - CONFIG.EMAIL = true - result = await sendEmailTranslated({ - receiver: { - to: 'receiver@mail.org', - cc: 'support@gradido.net', - }, - template: 'accountMultiRegistration', - locals: { - locale: 'en', - }, - }) - }) - - it('calls the transporter', () => { - expect(createTransport).toBeCalledWith({ - host: testMailServerHost, - port: testMailServerPort, - secure: false, - requireTLS: true, - auth: { - user: 'user', - pass: 'pwd', - }, - }) - }) - - describe('call of "sendEmailTranslated"', () => { - it('has expected result', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'receiver@mail.org', - cc: 'support@gradido.net', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Try To Register Again With Your Email', - html: expect.stringContaining('Try To Register Again With Your Email'), - text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), - }), - }) - }) - }) - - it.skip('calls "i18n.setLocale" with "en"', () => { - expect(i18n.setLocale).toBeCalledWith('en') - }) - - it.skip('calls "i18n.__" for translation', () => { - expect(i18n.__).toBeCalled() - }) - }) - - describe('with email EMAIL_TEST_MODUS true', () => { - beforeEach(async () => { - jest.clearAllMocks() - CONFIG.EMAIL = true - CONFIG.EMAIL_TEST_MODUS = true - result = await sendEmailTranslated({ - receiver: { - to: 'receiver@mail.org', - cc: 'support@gradido.net', - }, - template: 'accountMultiRegistration', - locals: { - locale: 'en', - }, - }) - }) - - it('call of "sendEmailTranslated" with faked "to"', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: CONFIG.EMAIL_TEST_RECEIVER, - cc: 'support@gradido.net', - from: `Gradido (emails.general.doNotAnswer) <${CONFIG.EMAIL_SENDER}>`, - attachments: expect.any(Array), - subject: 'Try To Register Again With Your Email', - html: expect.stringContaining('Try To Register Again With Your Email'), - text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), - }), - }) - }) - }) -}) diff --git a/backend/src/emails/sendEmailTranslated.ts b/backend/src/emails/sendEmailTranslated.ts deleted file mode 100644 index 5b95cd7ad..000000000 --- a/backend/src/emails/sendEmailTranslated.ts +++ /dev/null @@ -1,118 +0,0 @@ -import path from 'path' - -import Email from 'email-templates' -import i18n from 'i18n' -import { createTransport } from 'nodemailer' - -import { CONFIG } from '@/config' -import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -import { getLogger } from 'log4js' - -const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.emails.sendEmailTranslated`) - -export const sendEmailTranslated = async ({ - receiver, - template, - locals, -}: { - receiver: { - to: string - cc?: string - } - template: string - locals: Record -}): Promise | boolean | null> => { - // TODO: test the calling order of 'i18n.setLocale' for example: language of logging 'en', language of email receiver 'es', reset language of current user 'de' - - if (!CONFIG.EMAIL) { - logger.info(`Emails are disabled via config...`) - return null - } - - // because language of receiver can differ from language of current user who triggers the sending - // const rememberLocaleToRestore = i18n.getLocale() - - i18n.setLocale('en') // for logging - logger.info( - `send Email: language=${locals.locale as string} to=${receiver.to.substring(0, 3)}...` + - (receiver.cc ? `, cc=${receiver.cc.substring(0, 3)}...` : '') + - `, subject=${i18n.__('emails.' + template + '.subject')}`, - ) - - if (CONFIG.EMAIL_TEST_MODUS) { - logger.info( - `Testmodus=ON: change receiver from ${receiver.to} to ${CONFIG.EMAIL_TEST_RECEIVER}`, - ) - receiver.to = CONFIG.EMAIL_TEST_RECEIVER - } - const transport = createTransport({ - host: CONFIG.EMAIL_SMTP_HOST, - port: CONFIG.EMAIL_SMTP_PORT, - secure: false, // true for 465, false for other ports - requireTLS: CONFIG.EMAIL_TLS, - auth: { - user: CONFIG.EMAIL_USERNAME, - pass: CONFIG.EMAIL_PASSWORD, - }, - }) - - i18n.setLocale(locals.locale as string) // for email - - // TESTING: see 'README.md' - const email = new Email({ - message: { - from: `Gradido (${i18n.__('emails.general.doNotAnswer')}) <${CONFIG.EMAIL_SENDER}>`, - }, - send: CONFIG.EMAIL, - transport, - preview: false, - // i18n, // is only needed if you don't install i18n - }) - - const resultSend = await email - .send({ - template: path.join(__dirname, 'templates', template), - message: { - ...receiver, - attachments: [ - { - filename: 'gradido-header.jpeg', - path: path.join(__dirname, 'templates/includes/gradido-header.jpeg'), - cid: 'gradidoheader', - }, - { - filename: 'facebook-icon.png', - path: path.join(__dirname, 'templates/includes/facebook-icon.png'), - cid: 'facebookicon', - }, - { - filename: 'telegram-icon.png', - path: path.join(__dirname, 'templates/includes/telegram-icon.png'), - cid: 'telegramicon', - }, - { - filename: 'twitter-icon.png', - path: path.join(__dirname, 'templates/includes/twitter-icon.png'), - cid: 'twittericon', - }, - { - filename: 'youtube-icon.png', - path: path.join(__dirname, 'templates/includes/youtube-icon.png'), - cid: 'youtubeicon', - }, - { - filename: 'chatbox-icon.png', - path: path.join(__dirname, 'templates/includes/chatbox-icon.png'), - cid: 'chatboxicon', - }, - ], - }, - locals, // the 'locale' in here seems not to be used by 'email-template', because it doesn't work if the language isn't set before by 'i18n.setLocale' - }) - .catch((error: unknown) => { - logger.error('Error sending notification email', error) - return error - }) - - return resultSend -} diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts deleted file mode 100644 index 74eb940ed..000000000 --- a/backend/src/emails/sendEmailVariants.test.ts +++ /dev/null @@ -1,623 +0,0 @@ -import { ApolloServerTestClient } from 'apollo-server-testing' -import { Decimal } from 'decimal.js-light' -import { DataSource } from 'typeorm' - -import { testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' -import { getLogger } from 'config-schema/test/testSetup' - -import { CONFIG } from '@/config' - -import * as sendEmailTranslatedApi from './sendEmailTranslated' -import { - sendAccountActivationEmail, - sendAccountMultiRegistrationEmail, - sendAddedContributionMessageEmail, - sendContributionChangedByModeratorEmail, - sendContributionConfirmedEmail, - sendContributionDeletedEmail, - sendContributionDeniedEmail, - sendResetPasswordEmail, - sendTransactionLinkRedeemedEmail, - sendTransactionReceivedEmail, -} from './sendEmailVariants' - -const testMailServerHost = 'localhost' -const testMailServerPort = 1025 -const testMailTLS = false - -CONFIG.EMAIL_SENDER = 'info@gradido.net' -CONFIG.EMAIL_SMTP_HOST = testMailServerHost -CONFIG.EMAIL_SMTP_PORT = testMailServerPort -CONFIG.EMAIL_TLS = testMailTLS - -jest.mock('nodemailer', () => { - return { - __esModule: true, - createTransport: jest.fn(() => { - return { - sendMail: () => { - return { - messageId: 'message', - } - }, - } - }), - } -}) - -let con: DataSource -let testEnv: { - mutate: ApolloServerTestClient['mutate'] - query: ApolloServerTestClient['query'] - con: DataSource -} - -beforeAll(async () => { - testEnv = await testEnvironment(getLogger('apollo'), localization) - con = testEnv.con -}) - -afterAll(async () => { - await con.destroy() -}) - -const sendEmailTranslatedSpy = jest.spyOn(sendEmailTranslatedApi, 'sendEmailTranslated') - -describe('sendEmailVariants', () => { - let result: any - const contributionFrontendLink = - 'https://gradido.net/contributions/own-contributions/1#contributionListItem-1' - - describe('sendAddedContributionMessageEmail', () => { - beforeAll(async () => { - result = await sendAddedContributionMessageEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - message: 'My message.', - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'addedContributionMessage', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - message: 'My message.', - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Message about your common good contribution', - html: expect.any(String), - text: expect.stringContaining('MESSAGE ABOUT YOUR COMMON GOOD CONTRIBUTION'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendAccountActivationEmail', () => { - beforeAll(async () => { - result = await sendAccountActivationEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - activationLink: 'http://localhost/checkEmail/6627633878930542284', - timeDurationObject: { hours: 23, minutes: 30 }, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'accountActivation', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - activationLink: 'http://localhost/checkEmail/6627633878930542284', - timeDurationObject: { hours: 23, minutes: 30 }, - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Email Verification', - html: expect.any(String), - text: expect.stringContaining('EMAIL VERIFICATION'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendAccountMultiRegistrationEmail', () => { - beforeAll(async () => { - result = await sendAccountMultiRegistrationEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'accountMultiRegistration', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Try To Register Again With Your Email', - html: expect.any(String), - text: expect.stringContaining('TRY TO REGISTER AGAIN WITH YOUR EMAIL'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - }) - - describe('sendContributionConfirmedEmail', () => { - beforeAll(async () => { - result = await sendContributionConfirmedEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionAmount: new Decimal(23.54), - contributionFrontendLink, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'contributionConfirmed', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionAmount: '23.54', - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - contributionFrontendLink, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Your contribution to the common good was confirmed', - html: expect.any(String), - text: expect.stringContaining('YOUR CONTRIBUTION TO THE COMMON GOOD WAS CONFIRMED'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendContributionChangedByModeratorEmail', () => { - beforeAll(async () => { - result = await sendContributionChangedByModeratorEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionMemoUpdated: 'This is a better contribution memo.', - contributionFrontendLink, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'contributionChangedByModerator', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionMemoUpdated: 'This is a better contribution memo.', - contributionFrontendLink, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Your common good contribution has been changed', - html: expect.any(String), - text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION HAS BEEN CHANGED'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendContributionDeniedEmail', () => { - beforeAll(async () => { - result = await sendContributionDeniedEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'contributionDenied', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - }, - }) - }) - }) - - describe('result', () => { - it('has expected result', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Your common good contribution was rejected', - html: expect.any(String), - text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS REJECTED'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendContributionDeletedEmail', () => { - beforeAll(async () => { - result = await sendContributionDeletedEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'contributionDeleted', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - contributionMemo: 'My contribution.', - contributionFrontendLink, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Your common good contribution was deleted', - html: expect.any(String), - text: expect.stringContaining('YOUR COMMON GOOD CONTRIBUTION WAS DELETED'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendResetPasswordEmail', () => { - beforeAll(async () => { - result = await sendResetPasswordEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - resetLink: 'http://localhost/reset-password/3762660021544901417', - timeDurationObject: { hours: 23, minutes: 30 }, - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'resetPassword', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - resetLink: 'http://localhost/reset-password/3762660021544901417', - timeDurationObject: { hours: 23, minutes: 30 }, - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Reset password', - html: expect.any(String), - text: expect.stringContaining('RESET PASSWORD'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendTransactionLinkRedeemedEmail', () => { - beforeAll(async () => { - result = await sendTransactionLinkRedeemedEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - senderEmail: 'bibi@bloxberg.de', - transactionMemo: 'You deserve it! 🙏🏼', - transactionAmount: new Decimal(17.65), - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'transactionLinkRedeemed', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - senderEmail: 'bibi@bloxberg.de', - transactionMemo: 'You deserve it! 🙏🏼', - transactionAmount: '17.65', - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Bibi Bloxberg has redeemed your Gradido link', - html: expect.any(String), - text: expect.stringContaining('BIBI BLOXBERG HAS REDEEMED YOUR GRADIDO LINK'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) - - describe('sendTransactionReceivedEmail', () => { - beforeAll(async () => { - result = await sendTransactionReceivedEmail({ - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - language: 'en', - memo: 'Du bist schon lustiger ;)', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - senderEmail: 'bibi@bloxberg.de', - transactionAmount: new Decimal(37.4), - }) - }) - - describe('calls "sendEmailTranslated"', () => { - it('with expected parameters', () => { - expect(sendEmailTranslatedSpy).toBeCalledWith({ - receiver: { - to: 'Peter Lustig ', - }, - template: 'transactionReceived', - locals: { - firstName: 'Peter', - lastName: 'Lustig', - locale: 'en', - memo: 'Du bist schon lustiger ;)', - senderFirstName: 'Bibi', - senderLastName: 'Bloxberg', - senderEmail: 'bibi@bloxberg.de', - transactionAmount: '37.40', - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) - }) - }) - - describe('result', () => { - it('is the expected object', () => { - expect(result).toMatchObject({ - originalMessage: expect.objectContaining({ - to: 'Peter Lustig ', - from: 'Gradido (emails.general.doNotAnswer) ', - attachments: expect.any(Array), - subject: 'Bibi Bloxberg has sent you 37.40 Gradido', - html: expect.any(String), - text: expect.stringContaining('BIBI BLOXBERG HAS SENT YOU 37.40 GRADIDO'), - }), - }) - }) - - it('has the correct html as snapshot', () => { - expect(result.originalMessage.html).toMatchSnapshot() - }) - }) - }) -}) diff --git a/backend/src/emails/sendEmailVariants.ts b/backend/src/emails/sendEmailVariants.ts deleted file mode 100644 index aac726002..000000000 --- a/backend/src/emails/sendEmailVariants.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { Decimal } from 'decimal.js-light' - -import { CONFIG } from '@/config' -import { decimalSeparatorByLanguage } from 'core' - -import { sendEmailTranslated } from './sendEmailTranslated' - -export interface ContributionEmailCommonData { - firstName: string - lastName: string - email: string - language: string - senderFirstName: string - senderLastName: string - contributionMemo: string - contributionFrontendLink: string -} - -function toContributionEmailLocales(data: ContributionEmailCommonData): Record { - return { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - senderFirstName: data.senderFirstName, - senderLastName: data.senderLastName, - contributionMemo: data.contributionMemo, - contributionFrontendLink: data.contributionFrontendLink, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - } -} - -export const sendAddedContributionMessageEmail = ( - data: ContributionEmailCommonData & { - message: string - }, -): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { - to: `${data.firstName} ${data.lastName} <${data.email}>`, - }, - template: 'addedContributionMessage', - locals: { - ...toContributionEmailLocales(data), - message: data.message, - }, - }) -} - -export const sendAccountActivationEmail = (data: { - firstName: string - lastName: string - email: string - language: string - activationLink: string - timeDurationObject: Record - logoUrl?: string | null -}): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'accountActivation', - locals: { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - activationLink: data.activationLink, - timeDurationObject: data.timeDurationObject, - logoUrl: data.logoUrl, - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) -} - -export const sendAccountMultiRegistrationEmail = (data: { - firstName: string - lastName: string - email: string - language: string -}): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'accountMultiRegistration', - locals: { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) -} - -export const sendContributionConfirmedEmail = ( - data: ContributionEmailCommonData & { - contributionAmount: Decimal - }, -): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'contributionConfirmed', - locals: { - ...toContributionEmailLocales(data), - contributionAmount: decimalSeparatorByLanguage(data.contributionAmount, data.language), - }, - }) -} - -export const sendContributionChangedByModeratorEmail = ( - data: ContributionEmailCommonData & { - contributionMemoUpdated: string - }, -): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'contributionChangedByModerator', - locals: { - ...toContributionEmailLocales(data), - contributionMemoUpdated: data.contributionMemoUpdated, - }, - }) -} - -export const sendContributionDeletedEmail = ( - data: ContributionEmailCommonData, -): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'contributionDeleted', - locals: toContributionEmailLocales(data), - }) -} - -export const sendContributionDeniedEmail = ( - data: ContributionEmailCommonData, -): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'contributionDenied', - locals: toContributionEmailLocales(data), - }) -} - -export const sendResetPasswordEmail = (data: { - firstName: string - lastName: string - email: string - language: string - resetLink: string - timeDurationObject: Record -}): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'resetPassword', - locals: { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - resetLink: data.resetLink, - timeDurationObject: data.timeDurationObject, - resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD, - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) -} - -export const sendTransactionLinkRedeemedEmail = (data: { - firstName: string - lastName: string - email: string - language: string - senderFirstName: string - senderLastName: string - senderEmail: string - transactionMemo: string - transactionAmount: Decimal -}): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'transactionLinkRedeemed', - locals: { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - senderFirstName: data.senderFirstName, - senderLastName: data.senderLastName, - senderEmail: data.senderEmail, - transactionMemo: data.transactionMemo, - transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language), - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) -} - -export const sendTransactionReceivedEmail = (data: { - firstName: string - lastName: string - email: string - language: string - senderFirstName: string - senderLastName: string - senderEmail: string - memo: string - transactionAmount: Decimal -}): Promise | boolean | null> => { - return sendEmailTranslated({ - receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, - template: 'transactionReceived', - locals: { - firstName: data.firstName, - lastName: data.lastName, - locale: data.language, - memo: data.memo, - senderFirstName: data.senderFirstName, - senderLastName: data.senderLastName, - senderEmail: data.senderEmail, - transactionAmount: decimalSeparatorByLanguage(data.transactionAmount, data.language), - supportEmail: CONFIG.COMMUNITY_SUPPORT_MAIL, - communityURL: CONFIG.COMMUNITY_URL, - }, - }) -} diff --git a/backend/src/emails/templates/accountActivation/html.pug b/backend/src/emails/templates/accountActivation/html.pug deleted file mode 100644 index 6b5dd41c3..000000000 --- a/backend/src/emails/templates/accountActivation/html.pug +++ /dev/null @@ -1,18 +0,0 @@ -extend ../layout.pug - -block content - if logoUrl - img(src=logoUrl, alt="Banner", style="max-width: 680px; max-height: 250px;border-radius:20px") - h2= t('emails.accountActivation.title') - .text-block - include ../includes/salutation.pug - p= t('emails.accountActivation.emailRegistered') - .content - h2= t('emails.general.completeRegistration') - div(class="p_content")= t('emails.accountActivation.pleaseClickLink') - a.button-3(href=activationLink) #{t('emails.accountActivation.activateAccount')} - div(class="p_content")= t('emails.general.orCopyLink') - - a.clink(href=activationLink) #{activationLink} - - include ../includes/requestNewLink.pug diff --git a/backend/src/emails/templates/accountActivation/subject.pug b/backend/src/emails/templates/accountActivation/subject.pug deleted file mode 100644 index 81749a38e..000000000 --- a/backend/src/emails/templates/accountActivation/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.accountActivation.subject') diff --git a/backend/src/emails/templates/accountMultiRegistration/html.pug b/backend/src/emails/templates/accountMultiRegistration/html.pug deleted file mode 100644 index 4d568261b..000000000 --- a/backend/src/emails/templates/accountMultiRegistration/html.pug +++ /dev/null @@ -1,22 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.accountMultiRegistration.title') - .text-block - include ../includes/salutation.pug - p - = t('emails.accountMultiRegistration.emailReused') - br - = t('emails.accountMultiRegistration.emailExists') - .content - h2= t('emails.resetPassword.title') - div(class="p_content")= t('emails.accountMultiRegistration.onForgottenPasswordClickLink') - a.button-3(href=resendLink) #{t('emails.general.reset')} - div(class="p_content")= t('emails.general.orCopyLink') - - a.clink(href=resendLink) #{resendLink} - - h2(style="color: red")= t('emails.accountMultiRegistration.contactSupport') - div(class="p_content")= t('emails.accountMultiRegistration.ifYouAreNotTheOne') - - a.clink(href='mailto:' + supportEmail)= supportEmail diff --git a/backend/src/emails/templates/accountMultiRegistration/subject.pug b/backend/src/emails/templates/accountMultiRegistration/subject.pug deleted file mode 100644 index fb130f0e4..000000000 --- a/backend/src/emails/templates/accountMultiRegistration/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.accountMultiRegistration.subject') diff --git a/backend/src/emails/templates/addedContributionMessage/html.pug b/backend/src/emails/templates/addedContributionMessage/html.pug deleted file mode 100644 index df5ba35c4..000000000 --- a/backend/src/emails/templates/addedContributionMessage/html.pug +++ /dev/null @@ -1,16 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.addedContributionMessage.title') - .text-block - include ../includes/salutation.pug - p= t('emails.addedContributionMessage.commonGoodContributionMessage', { senderFirstName, senderLastName, contributionMemo }) - .content - h2= t('emails.addedContributionMessage.readMessage') - div(class="p_content") - p= t('emails.addedContributionMessage.message', { message }) - p= t('emails.addedContributionMessage.toSeeAndAnswerMessage') - - a.button-3(href=`${contributionFrontendLink}`) #{t('emails.general.toAccount')} - - include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/addedContributionMessage/subject.pug b/backend/src/emails/templates/addedContributionMessage/subject.pug deleted file mode 100644 index 4ac85fa23..000000000 --- a/backend/src/emails/templates/addedContributionMessage/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.addedContributionMessage.subject') diff --git a/backend/src/emails/templates/contributionChangedByModerator/html.pug b/backend/src/emails/templates/contributionChangedByModerator/html.pug deleted file mode 100644 index 46bcd4ae1..000000000 --- a/backend/src/emails/templates/contributionChangedByModerator/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.contributionChangedByModerator.title') - .text-block - include ../includes/salutation.pug - p= t('emails.contributionChangedByModerator.text', { contributionMemo, senderFirstName, senderLastName, contributionMemoUpdated }) - .content - include ../includes/contributionDetailsCTA.pug - include ../includes/doNotReply.pug \ No newline at end of file diff --git a/backend/src/emails/templates/contributionChangedByModerator/subject.pug b/backend/src/emails/templates/contributionChangedByModerator/subject.pug deleted file mode 100644 index 791cee555..000000000 --- a/backend/src/emails/templates/contributionChangedByModerator/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.contributionChangedByModerator.subject') diff --git a/backend/src/emails/templates/contributionConfirmed/html.pug b/backend/src/emails/templates/contributionConfirmed/html.pug deleted file mode 100644 index 310993d97..000000000 --- a/backend/src/emails/templates/contributionConfirmed/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.contributionConfirmed.title') - .text-block - include ../includes/salutation.pug - p= t('emails.contributionConfirmed.commonGoodContributionConfirmed', { contributionMemo, senderFirstName, senderLastName, amountGDD: contributionAmount }) - .content - include ../includes/contributionDetailsCTA.pug - include ../includes/doNotReply.pug \ No newline at end of file diff --git a/backend/src/emails/templates/contributionConfirmed/subject.pug b/backend/src/emails/templates/contributionConfirmed/subject.pug deleted file mode 100644 index c5bd41421..000000000 --- a/backend/src/emails/templates/contributionConfirmed/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.contributionConfirmed.subject') diff --git a/backend/src/emails/templates/contributionDeleted/html.pug b/backend/src/emails/templates/contributionDeleted/html.pug deleted file mode 100644 index daf54227d..000000000 --- a/backend/src/emails/templates/contributionDeleted/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.contributionDeleted.title') - .text-block - include ../includes/salutation.pug - p= t('emails.contributionDeleted.commonGoodContributionDeleted', { contributionMemo, senderFirstName, senderLastName }) - .content - include ../includes/contributionDetailsCTA.pug - include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/contributionDeleted/subject.pug b/backend/src/emails/templates/contributionDeleted/subject.pug deleted file mode 100644 index 024588472..000000000 --- a/backend/src/emails/templates/contributionDeleted/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.contributionDeleted.subject') diff --git a/backend/src/emails/templates/contributionDenied/html.pug b/backend/src/emails/templates/contributionDenied/html.pug deleted file mode 100644 index d30653acd..000000000 --- a/backend/src/emails/templates/contributionDenied/html.pug +++ /dev/null @@ -1,10 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.contributionDenied.title') - .text-block - include ../includes/salutation.pug - p= t('emails.contributionDenied.commonGoodContributionDenied', { contributionMemo, senderFirstName, senderLastName }) - .content - include ../includes/contributionDetailsCTA.pug - include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/contributionDenied/subject.pug b/backend/src/emails/templates/contributionDenied/subject.pug deleted file mode 100644 index 57431e56e..000000000 --- a/backend/src/emails/templates/contributionDenied/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.contributionDenied.subject') diff --git a/backend/src/emails/templates/includes/Chatbox.svg b/backend/src/emails/templates/includes/Chatbox.svg deleted file mode 100644 index 4eb68e0bb..000000000 --- a/backend/src/emails/templates/includes/Chatbox.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/backend/src/emails/templates/includes/answear_button.svg b/backend/src/emails/templates/includes/answear_button.svg deleted file mode 100644 index f45fedc90..000000000 --- a/backend/src/emails/templates/includes/answear_button.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - Jetzt antworten - - - diff --git a/backend/src/emails/templates/includes/chatbox-icon.png b/backend/src/emails/templates/includes/chatbox-icon.png deleted file mode 100644 index a25c7c209cb79912e5adab4b7732ca9858955e17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9F5he4R}c>anMprB-l zYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt&fkT^vI^I^Rxpt*$!I@bcilmcXRrOkP_`0>HiiLiq(xj+>07kDqMfHY{##Q zlh#;pR2gl4c_ETL@xfeC%dqcrr^TpWs_@NqndEL~zIij>tP8)bE11vjc5$h#TT}z| O8-u5-pUXO@geCw$1$z7d diff --git a/backend/src/emails/templates/includes/chatbox-icon.pug b/backend/src/emails/templates/includes/chatbox-icon.pug deleted file mode 100644 index 62775b0f0..000000000 --- a/backend/src/emails/templates/includes/chatbox-icon.pug +++ /dev/null @@ -1,6 +0,0 @@ -span.chatbox-wrapper - img.bi-chatbox( - alt="chatbox" - loading="lazy" - src="cid:chatboxicon" - ) \ No newline at end of file diff --git a/backend/src/emails/templates/includes/contributionDetailsCTA.pug b/backend/src/emails/templates/includes/contributionDetailsCTA.pug deleted file mode 100644 index ae3b77e6a..000000000 --- a/backend/src/emails/templates/includes/contributionDetailsCTA.pug +++ /dev/null @@ -1,7 +0,0 @@ -//- -h2= t('emails.general.contributionDetails') -div(class="p_content")= t('emails.contribution.toSeeContributionsAndMessages') -a.button-3(href=`${contributionFrontendLink}`) #{t('emails.general.toAccount')} -div(class="p_content")= t('emails.general.orCopyLink') - -a.clink(href=`${contributionFrontendLink}`) #{`${contributionFrontendLink}`} \ No newline at end of file diff --git a/backend/src/emails/templates/includes/doNotReply.pug b/backend/src/emails/templates/includes/doNotReply.pug deleted file mode 100644 index 506a5d0db..000000000 --- a/backend/src/emails/templates/includes/doNotReply.pug +++ /dev/null @@ -1 +0,0 @@ -div(class="p_content")= t('emails.general.pleaseDoNotReply') \ No newline at end of file diff --git a/backend/src/emails/templates/includes/email.css b/backend/src/emails/templates/includes/email.css deleted file mode 100644 index 5110c3882..000000000 --- a/backend/src/emails/templates/includes/email.css +++ /dev/null @@ -1,216 +0,0 @@ -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 100; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 100; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 100; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 200; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 200; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 200; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 300; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 300; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 300; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 400; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 400; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 400; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 500; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 500; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 500; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 600; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 600; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 600; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 700; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 700; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 700; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 800; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 800; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 800; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* vietnamese */ -/* @font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 900; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_c6Dpp_k.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} */ -/* latin-ext */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 900; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_cqDpp_k.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 900; - src: url(https://fonts.gstatic.com/s/worksans/v18/QGYsz_wNahGAdqQ43Rh_fKDp.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/backend/src/emails/templates/includes/facebook-icon.png b/backend/src/emails/templates/includes/facebook-icon.png deleted file mode 100644 index 1d880cf3e21f0eac022181f0540859e65c9d2635..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1449 zcmV;a1y=frP)WmhDt1z%7D7m zQj!Z6h7TAE@2=H})G ztJUgd0AnOiq$Rf=08dEX&gb(tj~_q2l#0x)3YeXp9a>&q{!~P+kQ_?Erj`I$6p=}# z)P(Q*e{V@vrwvKM7&A)pnurW<#fUAi0N`p61a|D)Tqo_*hU7GW zQn6V4z1_BL2ViDq=3Ep-cS#;;x2;P6%zK`9sZc0Px6@9wQ`s0Z7DdthUUObVgyfMZ zitZa@#@cDOsQ{4lwAMGQwYNz2cV?n{NcLN6Z)vS>kn}dwrsWVI=^110lDxQe6SD)r zy&woK0f?H_YuN*gG1s@7^CBW7FB)U6x2o5)2N+|>P0`~LH!=f;>1NRC@; z-&9KNtIgWh+Sh^fPVWGWiO5$XaR9W|p{rx8b^Mm}z!+1s*4~Q^l=>edP3J{KNS@GI zhhZ4%+7KwEsv()bni%zdMmE$aiNtdN$qN}NT~2yH^0ka?sOh^PBBCml%3%PfvQ*v( zq}|V3>pNAcR1T~7rA4O7dx3b#e_oM1*==LG1<8{+lE+*K2k=FMvPVto|0smDSX1t5Myt$I2D0GtItDK*&Ei;*tjatMgB)~52B*&!~6z*0^rwd7(Ms! zi^b7K^^GxKlKiAWn|#`~)lf<;}yhgz@@VZEGUwhp3C(TB%dh& zPrGeMw*c@|0eIYPL%Ick#|prMPSZ=aGXMzSf%1L-1S9^n<%7RjAqP}2F08XDiy$IlHwl-x4 zfUE11t2Z2o1VM0zWLxQ`+X0f(K@i+oU%nwl1^~+%K6v_OK-_m)JHgAj=W5!5+)2kCBfR_NqTXp+2ZQ50`tFO$6y!v+_dA64p zOC+aBo^988k-ckkdlx77uFj?*WIem`@^litetrIbG9Al@qI{v(00000NkvXXu0mjf DhkUKj diff --git a/backend/src/emails/templates/includes/footer.pug b/backend/src/emails/templates/includes/footer.pug deleted file mode 100644 index 91a0e4543..000000000 --- a/backend/src/emails/templates/includes/footer.pug +++ /dev/null @@ -1,77 +0,0 @@ -footer - .w-container(class="footer_01") - .socialmedia - a.slink( - target="_blank" - href="https://www.facebook.com/groups/Gradido/" - ) - img.bi-facebook( - alt="facebook" - loading="lazy" - src="cid:facebookicon" - ) - a.slink( - target="_blank" - href="https://t.me/GradidoGruppe" - ) - img.bi-telegram( - alt="Telegram" - loading="lazy" - src="cid:telegramicon" - ) - a.slink( - target="_blank" - href="https://twitter.com/gradido" - ) - img.bi-twitter( - alt="Twitter" - loading="lazy" - src="cid:twittericon" - ) - a.slink( - target="_blank" - href="https://www.youtube.com/c/GradidoNet" - ) - img.bi-youtube( - alt="youtube" - loading="lazy" - src="cid:youtubeicon" - ) - .line - .footer - div(class="footer_p1")= t("emails.footer.contactOurSupport") - a( - class="footer_p2" - href='mailto:' + t("emails.footer.supportEmail") - )= t("emails.footer.supportEmail") - div - img.image( - alt="Gradido Logo" - src="https://gdd.gradido.net/img/brand/green.png" - ) - div - a( - class="terms_of_use" - href="https://gradido.net/de/impressum/" - target="_blank" - )= t("emails.footer.imprint") - br - a( - class="terms_of_use" - href="https://gradido.net/de/datenschutz/" - target="_blank" - )= t("emails.footer.privacyPolicy") - div(class="footer_p1") - | Gradido-Akademie - br - | Institut für Wirtschaftsbionik - br - | Pfarrweg 2 - br - | 74653 Künzelsau - br - | Deutschland - br - br - br - diff --git a/backend/src/emails/templates/includes/gradido-header.jpeg b/backend/src/emails/templates/includes/gradido-header.jpeg deleted file mode 100644 index 38a5c3a80f090b8973db6d603d406249f7af7f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9427 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 diff --git a/backend/src/emails/templates/includes/greeting.pug b/backend/src/emails/templates/includes/greeting.pug deleted file mode 100644 index 6693e23ca..000000000 --- a/backend/src/emails/templates/includes/greeting.pug +++ /dev/null @@ -1,6 +0,0 @@ -//- This sets the greeting at the end of every e-mail -.text-block - p - = t('emails.general.sincerelyYours') - br - = t('emails.general.yourGradidoTeam') \ No newline at end of file diff --git a/backend/src/emails/templates/includes/header.pug b/backend/src/emails/templates/includes/header.pug deleted file mode 100644 index 3160d3e2b..000000000 --- a/backend/src/emails/templates/includes/header.pug +++ /dev/null @@ -1,13 +0,0 @@ -header - .head - //- TODO - //- when https://gdd.gradido.net/img/gradido-email-header.jpg is on production, - //- replace this URL by https://gdd.gradido.net/img/brand/gradido-email-header.png - img.head-logo( - alt="Gradido Logo" - loading="lazy" - src="cid:gradidoheader" - ) - - - diff --git a/backend/src/emails/templates/includes/requestNewLink.pug b/backend/src/emails/templates/includes/requestNewLink.pug deleted file mode 100644 index 8baa3d6df..000000000 --- a/backend/src/emails/templates/includes/requestNewLink.pug +++ /dev/null @@ -1,10 +0,0 @@ -//- -requestNewLink - h2= t('emails.general.requestNewLink') - - if timeDurationObject.minutes == 0 - div(class="p_content")= t('emails.general.linkValidity', { hours: timeDurationObject.hours }) - else - div(class="p_content")= t('emails.general.linkValidityWithMinutes', { hours: timeDurationObject.hours, minutes: timeDurationObject.minutes }) - - a.button-4(href=resendLink) #{t('emails.general.newLink')} \ No newline at end of file diff --git a/backend/src/emails/templates/includes/salutation.pug b/backend/src/emails/templates/includes/salutation.pug deleted file mode 100644 index 3e2591951..000000000 --- a/backend/src/emails/templates/includes/salutation.pug +++ /dev/null @@ -1 +0,0 @@ -p= t('emails.general.helloName', { firstName, lastName }) diff --git a/backend/src/emails/templates/includes/telegram-icon.png b/backend/src/emails/templates/includes/telegram-icon.png deleted file mode 100644 index 4c36ff66148cb69d8c8f9373b33bca573c251ed8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2159 zcmV-#2$1)QP)bMFuniA}Vr(Ws3f zX=+J~xF)q|Qi+NFAht>4#}8A5HmO9usx}fq(cTEGv}W7Iq&=4^ZB0l5?w~ISX?6ME=fa@mXo|4z+&fI z))k{%kk(V>d{nC<*|qmvj%wRg&6jhomIEO!9dE zdx9W{($zFY2b?%@B0DxV_8`e&Nq3~hTMv@QCGGC-@87;+#fl55aCS;iDwP&pzI^#> z03MdKCtfU*0%61bZ&v>4o zDqCxZtJUg(`DQ!-NV>6Ftsbz}4kwXo$pMnQD2lc?=XOcDu00jI4@uWK=XOO=v_+EF zicHfXAjz}VJ}c?o&Q-j6Ai3Z7{dFX(bJc6w1FW@=zuSxl07>^+Yaee`Z_XZItsQpG z?MhFrs}Ez$mweyf-ROBk2gI}ef%!blvcpRgB-dJNH_Rxn|5GZJ7M088Q+Vh0 z_T9!g&+`WB4^UV1fcR85uZ<`90?98LV{#-nClp`ooZEB-U+u?<6DP9cX^4$H}e)h-ZN0TL7K|u*3KLgL8$l!Z7RsurZU#{3Vymy;T3KR4Uz6E|=Th ztVy~D05Zj5afx$osN3V8Q)em60^m2~h)B06PZ;27cZ^`B@Q$;ioQMyts|zG626E7#R5c;Naj}v(=TTr#7hqwkxTn0SAC8ov#aw`Ty{ zkW^688^)Mt;;rfNb{ej)TaZS<&thJx4R4SvAHq{#sV06KP1s_goe6d(u z0^p{kddvpr+=YxW=7OZA6QQIv)oS&nD2iSMun)lAAP7oxDe9bi!a4WAELeZ{yCsjJtw{Oga41jY0KA1p(+W>3^u=()e!zW4Z%VaWpbGh7Ttxgz*U#M2AKLqgJ z>GCA^FI~FybIX=3n`l$-)EofdTt?C<0EKp>NiGNQNTpJFB#NTr0QLg7OVZs9M0WbV z|4@SC?hK@{1FYjZl_7aDjU^?HCp-qAk#XNH6bg@a+)#==faFO-ay{O;nJl`sdaynB6-N<^ZB!qUQUtN)E{C< zo*o(+`gf^R>Wu>&Z6oFJ|8hQ`KWhLW&cjQKn7VROISl}J-g)OZFcsx#3(mPT$N%%d z+fm^?0KT3U`7}&jNEQl(%dvyZTu0qGkXjGGq|K8zLqQNkB-=XG%?3`Q)(cKgdnRjb zJ`BSjg<-g`RnB6ucs+nyQ_}BvE$g&?VtP6aasZHIB)Pb;D;!|0y<5^j02?L!wNxs# z6p(Swr8)km4s}xw=;)fJm25n zzrFT<$^r3R*^_BBQrDPzdU{?50Bh|-B!4kW#z_{yz9@>eG?^gNngE}y&ojPaZSLvm zc>7Nx}umvm_tzegBWOvM>x6$7wDdh3`oY2SISfTsMPI62mb3^E;U(5-*XDEnK+p zsqyjg>q%~_-Q=_jNh5_q;Um*`z1NbYW)mnB3a35KTSv0oef7GFI8AO{qfGLKlTt31 z8zH%|d#YU>klZ*|2Kk&PG~f4kliWI2o%sxsTbo6)uO&;jKva#1-ZecTe)CO@2NHfU zVyzvPv~9lT50fmD+?eD7=h`PTNgK-LawC$~NJ`XDHz8?6(wd~k1J^#AyY}JawNGc$ lAeoN;%a5lUVZMJp|6hafLt8=zP{RNK002ovPDHLkV1k2FAsYYy diff --git a/backend/src/emails/templates/includes/twitter-icon.png b/backend/src/emails/templates/includes/twitter-icon.png deleted file mode 100644 index fffb9b59939b564a552879830d1244e319c9ba8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2002 zcmV;@2QB!CP)2v^jL`{t)V1_VYpM$PXVmRA|eAWko=M7c?U=;4MC~~@O}SQ zNry;oNn@WkBpoBUqg*b(o76UO0~|kod`le1uSmK%scj=c@_eCC*xuFEbu5XUNm4ir z!|phak1RIl0YK8taU35B!>~Jv-Mkt=QXvR}mz;BZCAFlJ*my{4an9`xg5V`dh56Xj z{RAWx!Z3VA(zfgp7Y-zU?|I&KlJQ*S>h^#z3}5`PIS&AmwuNE%V!d*6_JA-9yPb1; z^OLpkFvdLQdEUO+exJ1gs-yjp#r)0B2PDS|g~GkF%?>j*fbaXal6-41j`nFl^1P(Y zGp!S*jRBG<>CpA!JaA=-tok(VA3m)C!Z6&qSXOv>g5;Jk40ld@U;9w0RF;p8jh(>< zx3+IIE))ud&(&_AuId5RUETHSJaFY8=KHlTrg}hMUtj0Q$jCbjwWY0tnB*XUk4ajR zCo##39UUFFO`a!A^?;F)k?(wv&P$pgxu;MlY_ZlZvDV&Vt!*{N+)478>KVWkNM0tn z2f*tI>sdZLJpB0NbL}UPXcJK*L;xNlc{q)I6@PDOX(?H2pD2||f301YeNl6qoe(4dM?SbwKkaS0S_l7s3H0-0IXWI>VIu*ZQDq`k;L8@ z^KcsH0bq1=^z#6|LGsrr%y$6QPe9U_(g*+ml7E~0yI3p^d!F}Y06!t==3)N2wf4=l zbz5uy(9zNHmUHf|q_&c_0)UC4XeG(@X+;1St$iTr%H{IY0JZ`+F_)n+=64zD1pthU zj2s}jCaE3C^-&b9G}WL*>cdgzTyduN*4iW1+Ad?vBLL3KV&0RsUf=hdgCO{or0r?! zt4scSnk3EWzfP(-IhGAHC&V7^Qea^YnB%7Rb7iY7bN4+mg`g&S>0FYEP zk`i~HS~%x+Mp3k~UOCV6{BpVcLu+lZy}i8yz{a+=wp4>307$ZFZEHBzG?82*r8-gv z0FZp8+70*2*QQu3j-k%@P!Ezi$ZT;PlB=5l+?0W1-1EH0(gr2cqIyWXEC;F;#yQuS zfuQ-si4&j7K}aI>^z_^TpgAi~H9~E&GyolD#?c6-e&y?d@$yBq<1j2PEB}Cnw2X zL-J@|D>+GbU%q_#U{6m^M;?5Ws8lMScFrBhlar)K9yO&>X+YA+yojB14~>tHhfx%L zRZ>${zW)CHC1Yb_zag1r$vzE|PL@ig0RsTlJiI)y+BtV1ilRreko5QWFBuvddKJJI za?&-0NuMVNltVd@UL<+g81wCA%a+~dd0y(!dT(#<(xIWDS0&w-hqf7T2&f5+1VPZ7 zB*Bs7JI0u;aU8ccH8r`3iHY~EweRIIoH_p!OTx58#Ca zJfCsSJ=)yd{QRa(n?~{w*3;9|F)=am1LxdR0CJ58)k4x#!bIlKn56fNF+Xo_Z{M?S z-MYavf}$w;cpS%%0C)<(EonIBi)%w;R~@MYLGY}kXVMT$`mZtOu%y>oT3Y_HapT5+ z%vHWpsoWmN@mW=_SvcDYeeN49)F)?ucSc${~=kBw4CH8s)wSv zPHXeTwD9<}L$x3XzE%5;Tu&g`ZLQsZ)w^p8NuuxjZ(eU%B9e}k%jLVTou#I2EUHVy z9VE{$oV><@N-YpSL38D z3`p*pD}#K_y|w3g`$+E2U)I8ahzpWd^u1J4o6rDN#j@grsAVHYar+xN&Xn#>L4SS7-Ae kxfUPE%hR)Av0tD6KRO$}cDgFm=l}o!07*qoM6N<$f{G#L5&!@I diff --git a/backend/src/emails/templates/includes/webflow.css b/backend/src/emails/templates/includes/webflow.css deleted file mode 100644 index 45e4420c4..000000000 --- a/backend/src/emails/templates/includes/webflow.css +++ /dev/null @@ -1,166 +0,0 @@ -body{ - display: block; - font-family: "Work Sans", sans-serif; - font-size: 17px; - text-align: center; - text-align: -webkit-center; - justify-content: center; - padding: 0px; - margin: 0px; -} - -h2 { - margin-top: 15px; - color: #383838; -} - -.container { - max-width: 680px; - margin: 0 auto; - display: block; -} - -.head-logo { - width: 100%; - height: auto; -} - -.text-block { - margin-top: 20px; - color: #9ca0a8; -} - -.content { - display: block; - width: 78%; - margin: 40px 1% 40px 1%; - padding: 20px 10% 40px 10%; - border-radius: 24px; - background-image: linear-gradient(180deg, #f5f5f5, #f5f5f5); -} - -.p_content{ - margin: 15px 0 15px 0; - line-height: 26px; - color: #696c72; -} - -.clink { - line-break: anywhere; - margin-bottom: 40px; -} - -.button-3, -.button-4, -.button-5 { - display: inline-block; - padding: 9px 15px; - color: white; - border: 0; - line-height: inherit; - text-decoration: none; - cursor: pointer; - border-radius: 20px; - background-image: radial-gradient(circle farthest-corner at 0% 0%, #f9cd69, #c58d38); - box-shadow: 16px 13px 35px 0 rgba(56, 56, 56, 0.3); - margin: 25px 0 25px 0; - width: 50%; -} - -.button-4 { - background-image: radial-gradient(circle farthest-corner at 0% 0%, #616161, #c2c2c2); -} - -.button-5 { - background: linear-gradient(135deg, #53900c, #6e6e6e); - font-size: 20px; - font-weight: 600; - color: #f5f5f5; - width: auto; - box-shadow: 20px 20px 25px; - transition: all 0.3s ease; -} - -.button-5:hover { - transform: translateY(-5px); - box-shadow: 20px 25px 30px rgba(56, 56, 56, 0.4); -} - -.chatbox-wrapper { - margin-right: 8px; -} -.bi-chatbox { - margin-bottom: -5px; -} - -.child-right { - text-align: right; -} -.child-left { - text-align: left; -} - -.socialmedia { - display: flex; - margin-top: 40px; - max-width: 600px; - -} -.slink{ - width: 150px; -} - -.footer { - padding-bottom: 20px; -} - -.footer_p1 { - margin-top: 30px; - color: #9ca0a8; - margin-bottom: 30px; -} - -.footer_p2 { - color: #383838; - font-weight: bold; -} - - -.image { - width: 200px; - margin-top: 30px; - margin-bottom: 30px; -} - -.div-block { - display: table; - margin-top: 20px; - margin-bottom: 40px; - flex-direction: row; - justify-content: center; - align-items: center; -} - -.terms_of_use { - color: #9ca0a8; -} - -.text-block-3 { - color: #9ca0a8; - margin-bottom: 30px; -} - -.line_image, -.line { - width: 100%; - height: 13px; - margin-top: 40px; -} - -.line_image { - background-image: linear-gradient(90deg, #c58d38, #c58d38 0%, #f3cd7c 35%, #dbb056 54%, #eec05f 63%, #cc9d3d); -} - -.line { - background-image: linear-gradient(90deg, #c58d38, #f3cd7c 40%, #dbb056 55%, #eec05f 71%, #cc9d3d); -} diff --git a/backend/src/emails/templates/includes/youtube-icon.png b/backend/src/emails/templates/includes/youtube-icon.png deleted file mode 100644 index d135ba625d2749adad59d87623b082797418f5ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1802 zcmV+l2le=gP)A6O75=_ElNjVNA;O7-5TOgwnA%F_y_qafL{%!fVbMi4 zNR|-6MXj=dt|DavsEewq3JqC+h?I~8@`6PdEXo4mNTPBc>FVd_svY4G~Z@4@4fGwbI-f)-h0kHm*_I8)#?FB&q^AWbcE#700y0N z1ICyE0C3JN8Do|J%uAXfd7I=7l2?KtxZ6$p*bSjk6qNvsN_v6hh$JsPBqixO$v*=a zFO^DBXD#iZ1E!~^2bPzYUnV&w>6uQ+Z3fAkk}eerg$qMNLrWcznN>ioR@=Y2y806U zKbEw=12(k<$$J3K8)MD|L9mcXmM>8ft+l5ly$N72ixC+xPx4F{hL=goM}U_DDwWD1 zN#i6>`0zUoNs}Z;%jNP1X}PH#aP{id6LB2BBk5pTZZ|=4E|<%lEEbECX?P~h!`9ld zIF2WFTjK#h(!n^6C# zhcV`*Fbpqkb$?3-B%}SrZvN(X0+K7aT<-a;W`|83P^nZ7k^IMQ9PNETa!%6m&DIGU z#sEo_H2%0W9$1?qlQwO5;Ts%atv$6{R(PER$rIMvQyZ=~|Ebk#`&U+0X7KRV_T9#O zE|)vp96+t>0ZCN%xHcYGOT@g|eBnV4n4X>`h?_tl1`G78c%g(vyCA}u; zDIYl`$B;OHz*-JZQpHo)ElJ-jm&=Pjd|%AY&VFHWaq)cs!#;eHHM-NNuOY^m zAN9KN0C4#5;s56I`Bb5A3r2xt7LfFUj|7r;f*^Q5gAtifEEfMx@}EB3Mw|21YW09~ zZbb4*sa;F+u(kFWfbSV&E*Fc%86SnMkaQiu*VFPyj#R7F118zD@Xg!bPV>B^UpnW` z#&KMWqUdL{v$K6ZdRuIm_2DH;{%4IOuR#O=oOAz5skA@&?UVHLg@uKwYPI^Dul_{V zzcX-$jie*K0!V)B%T4%4;y8ZKTKl_Ow{CsOQ_Q@teo03R$t(`&$nK1D?o_>ApRQCY zKS;|p#w`2lCHb@g;OlviT=nH{fR;%s!rDU{W&^YG?eA&*qj<5J6J-52L zIu%9H*>2mA>`)tT2gq~o+=1LaNv~hKcI~U(w80oNkSVYr*_G|}ME37TMn*pDwhhKP z=RJ^h!vQ4k7-PO$DwV#!lb|Y#4M|~!$ug4f$-rF)N%u*u?>$s4{7NGiT|3}eh2aU6eajJc5VJKqjN zzC@BY@+7Y$)mW)VQ%R|m2SM;IfOpgCX@hV0kVuN;6%z!(-6WwW(wAPN7n% z4Ea{1NxB{c!CeCYNgbXSB>iTm#R#25qVw0j{6?D_E5Y#$hJ43b`6aY8+_V7>T0jrX;WLsR@fDKLjw>*cXtrO!9w{R!DwA@_u7az!>8Iz&U4{ z_6G8j`bh4T^m&qnrhS2flD-09Ult=t-Yk_$!$8x%fTW86+E!Gw!9Gd*06de(MC)(! zjME&*wcgu|+bKwTP%!Zz7%CJB7m^Ch#~LK>6$*t5jsFiEknEM6e<)V<7U!GmjMs(3 zd-m-46*A=59s$f7W6m{SSm%JFM~~hkd8W5E^$sM@v=&!yn6@ObQmOp)ajO!MG+8c} zztvh)y&)r%ED=XZ&h^f`?ta=H9LE|)t=a;5v`br(sQ+{vvf$+yf2 z7K_D6lBc_8T5mw|^mY~G+a^WBFuX+a+;-3GW{^C$U6m;Cq*%Iru{6mz5%kFPgyhY) zZ9I_j#E7+aED3*iW&JS86_Tghb^CRkv`RkHM`nPv*+J5ANvRZd6Otw+9Z%bM;K{MM sCkH2=9G&fikXC#q4^MA}-F|%jQ$FLp<@n27i2wiq07*qoM6N<$f^Fe$FaQ7m diff --git a/backend/src/emails/templates/layout.pug b/backend/src/emails/templates/layout.pug deleted file mode 100644 index 0995b2647..000000000 --- a/backend/src/emails/templates/layout.pug +++ /dev/null @@ -1,26 +0,0 @@ -doctype html -html(lang=locale) - head - meta( - content="multipart/html; charset=UTF-8" - http-equiv="content-type" - ) - meta( - name="viewport" - content="width=device-width, initial-scale=1" - ) - style. - .wf-force-outline-none[tabindex="-1"]:focus{outline:none;} - style - include includes/email.css - include includes/webflow.css - - body - div.container - include includes/header.pug - - .wrapper - block content - include includes/greeting.pug - - include includes/footer.pug diff --git a/backend/src/emails/templates/resetPassword/html.pug b/backend/src/emails/templates/resetPassword/html.pug deleted file mode 100644 index 4d4ed3f50..000000000 --- a/backend/src/emails/templates/resetPassword/html.pug +++ /dev/null @@ -1,16 +0,0 @@ -extends ../layout.pug - -block content - h2= t('emails.resetPassword.title') - .text-block - include ../includes/salutation.pug - p= t('emails.resetPassword.youOrSomeoneResetPassword') - .content - h2= t('emails.resetPassword.title') - div(class="p_content")= t('emails.resetPassword.pleaseClickLink') - a.button-3(href=resetLink) #{t('emails.general.reset')} - div(class="p_content")= t('emails.general.orCopyLink') - - a.clink(href=resetLink) #{resetLink} - - include ../includes/requestNewLink.pug diff --git a/backend/src/emails/templates/resetPassword/subject.pug b/backend/src/emails/templates/resetPassword/subject.pug deleted file mode 100644 index 21f277316..000000000 --- a/backend/src/emails/templates/resetPassword/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.resetPassword.subject') diff --git a/backend/src/emails/templates/transactionLinkRedeemed/html.pug b/backend/src/emails/templates/transactionLinkRedeemed/html.pug deleted file mode 100644 index 281ee9205..000000000 --- a/backend/src/emails/templates/transactionLinkRedeemed/html.pug +++ /dev/null @@ -1,18 +0,0 @@ -extend ../layout.pug - -block content - h2= t('emails.transactionLinkRedeemed.title', { senderFirstName, senderLastName }) - .text-block - include ../includes/salutation.pug - p= t('emails.transactionLinkRedeemed.hasRedeemedYourLink', { senderFirstName, senderLastName, senderEmail }) - .content - h2= t('emails.general.transactionDetails') - div(class="p_content")= t('emails.general.amountGDD', { amountGDD: transactionAmount }) - br - = t('emails.transactionLinkRedeemed.memo', { transactionMemo }) - br - = t('emails.general.detailsYouFindOnLinkToYourAccount') - - a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} - - include ../includes/doNotReply.pug diff --git a/backend/src/emails/templates/transactionLinkRedeemed/subject.pug b/backend/src/emails/templates/transactionLinkRedeemed/subject.pug deleted file mode 100644 index 9070b60b3..000000000 --- a/backend/src/emails/templates/transactionLinkRedeemed/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.transactionLinkRedeemed.subject', { senderFirstName, senderLastName }) diff --git a/backend/src/emails/templates/transactionReceived/html.pug b/backend/src/emails/templates/transactionReceived/html.pug deleted file mode 100644 index 4f9aa9c31..000000000 --- a/backend/src/emails/templates/transactionReceived/html.pug +++ /dev/null @@ -1,30 +0,0 @@ -extend ../layout.pug - -block content - mixin mailto(email, subject) - - var formattedSubject = encodeURIComponent(subject) - a(class!=attributes.class href=`mailto:${email}?subject=${formattedSubject}`) - block - - - var subject= t('emails.transactionReceived.replySubject', { senderFirstName, senderLastName, transactionAmount }) - h2= t('emails.transactionReceived.title', { senderFirstName, senderLastName, transactionAmount }) - .text-block - include ../includes/salutation.pug - p - = t('emails.transactionReceived.haveReceivedAmountGDDFrom', { transactionAmount, senderFirstName, senderLastName }) - | ( - +mailto(senderEmail, subject)=senderEmail - |). - .content - h2= t('emails.general.message') - .child-left - div(class="p_content")= memo - .child-right - +mailto(senderEmail, subject)(class="button-5") - include ../includes/chatbox-icon.pug - span #{t('emails.general.answerNow')} - - a.button-3(href=`${communityURL}/transactions`) #{t('emails.general.toAccount')} - - - diff --git a/backend/src/emails/templates/transactionReceived/subject.pug b/backend/src/emails/templates/transactionReceived/subject.pug deleted file mode 100644 index 872806ebc..000000000 --- a/backend/src/emails/templates/transactionReceived/subject.pug +++ /dev/null @@ -1 +0,0 @@ -= t('emails.transactionReceived.subject', { senderFirstName, senderLastName, transactionAmount }) From d9647183c5f76eec9dd32da9d7423466136cc112 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:45:34 +0100 Subject: [PATCH 139/226] better error message for validation error, fix jest error --- config-schema/src/validate.ts | 27 ++++++++++++++++----------- config-schema/test/testSetup.bun.ts | 3 ++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/config-schema/src/validate.ts b/config-schema/src/validate.ts index c566dfab7..83cf097b3 100644 --- a/config-schema/src/validate.ts +++ b/config-schema/src/validate.ts @@ -17,17 +17,22 @@ export function validate(schema: ObjectSchema, data: any) { throw new Error('missing key in config validation with joi: ' + details) } const value = err.context.value - const description = schemaJson.keys[key] - ? schema.describe().keys[key].flags.description - : 'No description available' - if (data[key] === undefined) { - throw new Error( - `Environment Variable '${key}' is missing. ${description}, details: ${details}`, - ) - } else { - throw new Error( - `Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`, - ) + try { + const description = schemaJson.keys[key] + ? schema.describe().keys[key].flags.description + : 'No description available' + if (data[key] === undefined) { + throw new Error( + `Environment Variable '${key}' is missing. ${description}, details: ${details}`, + ) + } else { + throw new Error( + `Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`, + ) + } + } catch (e) { + console.error('Error getting description for key ' + key + ': ' + e) + throw e } }) } diff --git a/config-schema/test/testSetup.bun.ts b/config-schema/test/testSetup.bun.ts index f64b81279..fd7153133 100644 --- a/config-schema/test/testSetup.bun.ts +++ b/config-schema/test/testSetup.bun.ts @@ -91,7 +91,8 @@ const getLoggerMocked = mock().mockImplementation((param: any) => { }) mock.module('log4js', () => ({ - getLogger: getLoggerMocked + getLogger: getLoggerMocked, + addLayout: jest.fn() })) export function getLogger(name: string) { From d07e9ba4139aeeff31f95c409913cc2f80b4ed0c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:45:50 +0100 Subject: [PATCH 140/226] prepare federation for using emails --- federation/esbuild.config.ts | 3 ++- federation/package.json | 6 +++++- federation/tsconfig.json | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/federation/esbuild.config.ts b/federation/esbuild.config.ts index 2ef5f88e5..879d96cbd 100644 --- a/federation/esbuild.config.ts +++ b/federation/esbuild.config.ts @@ -8,8 +8,9 @@ build({ target: 'node18.20.7', bundle: true, keepNames: true, + entryNames: '[name]', // legalComments: 'inline', - external: ['sodium-native'], + external: ['sodium-native', 'email-templates'], plugins: [esbuildDecorators()], minify: true, sourcemap: true, diff --git a/federation/package.json b/federation/package.json index 20176e3f9..057b22a98 100644 --- a/federation/package.json +++ b/federation/package.json @@ -8,13 +8,14 @@ "license": "Apache-2.0", "private": false, "scripts": { - "build": "ts-node ./esbuild.config.ts", + "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/src/emails/templates build/templates", "start": "cross-env TZ=UTC NODE_ENV=production node build/index.js", "start:bun": "cross-env TZ=UTC NODE_ENV=production bun build/index.js", "dev": "cross-env TZ=UTC nodemon -w src --ext ts,json,css -r tsconfig-paths/register src/index.ts", "dev:bun": "cross-env TZ=UTC bun --hot src/index.ts", "typecheck": "tsc --noEmit", "test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation jest --runInBand --forceExit --detectOpenHandles", + "test:bun": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation bun test", "test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation node --inspect-brk node_modules/.bin/jest --bail --runInBand --forceExit --detectOpenHandles", "test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation jest --coverage --runInBand --forceExit --detectOpenHandles", "lint": "biome check --error-on-warnings .", @@ -23,6 +24,7 @@ }, "dependencies": { "cross-env": "^7.0.3", + "email-templates": "^10.0.1", "sodium-native": "^3.4.1" }, "devDependencies": { @@ -60,6 +62,8 @@ "joi": "17.13.3", "lodash.clonedeep": "^4.5.0", "log4js": "^6.7.1", + "mkdirp": "^3.0.1", + "ncp": "^2.0.0", "nodemon": "^2.0.7", "prettier": "^3.5.3", "reflect-metadata": "^0.1.13", diff --git a/federation/tsconfig.json b/federation/tsconfig.json index 86b102fa6..c42e39505 100644 --- a/federation/tsconfig.json +++ b/federation/tsconfig.json @@ -6,6 +6,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "resolveJsonModule": true, // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ @@ -62,7 +63,7 @@ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": [ /* List of folders to include type definitions from. */ "node_modules/@types", - "../node_modules/@types" + "../node_modules/@types", ], // "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. */ @@ -84,6 +85,9 @@ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, + "include": [ + "../core/src/types", + ], "ts-node": { "swc": true } From 8bb05d172132c889dff90ef1cbb02df84e0067f1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:46:48 +0100 Subject: [PATCH 141/226] remove email locales, simplify i18n initalization --- backend/src/locales/de.json | 101 ----------------------------- backend/src/locales/en.json | 101 ----------------------------- backend/src/server/createServer.ts | 8 +-- backend/src/server/localization.ts | 3 +- 4 files changed, 5 insertions(+), 208 deletions(-) delete mode 100644 backend/src/locales/de.json delete mode 100644 backend/src/locales/en.json diff --git a/backend/src/locales/de.json b/backend/src/locales/de.json deleted file mode 100644 index 8b34f61f4..000000000 --- a/backend/src/locales/de.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "emails": { - "accountActivation": { - "activateAccount": "Konto aktivieren", - "emailRegistered": "deine E-Mail-Adresse wurde soeben bei Gradido registriert.", - "pleaseClickLink": "Klicke bitte hier, um die Registrierung abzuschließen und dein Gradido-Konto zu aktivieren.", - "subject": "E-Mail Überprüfung", - "title": "E-Mail Überprüfung" - }, - "accountMultiRegistration": { - "contactSupport": "Support kontaktieren", - "emailExists": "Es existiert jedoch zu deiner E-Mail-Adresse schon ein Konto.", - "emailReused": "deine E-Mail-Adresse wurde soeben erneut benutzt, um bei Gradido ein Konto zu registrieren.", - "ifYouAreNotTheOne": "Wenn du nicht versucht hast dich erneut zu registrieren, wende dich bitte an unseren Support:", - "onForgottenPasswordClickLink": "Solltest du dein Passwort vergessen haben, klicke bitte hier.", - "subject": "Erneuter Registrierungsversuch mit deiner E-Mail", - "title": "Erneuter Registrierungsversuch mit deiner E-Mail" - }, - "addedContributionMessage": { - "commonGoodContributionMessage": "du hast zu deinem Gemeinwohl-Beitrag „{contributionMemo}“ eine Nachricht von {senderFirstName} {senderLastName} erhalten.", - "readMessage": "Nachricht lesen und beantworten", - "subject": "Nachricht zu deinem Gemeinwohl-Beitrag", - "title": "Nachricht zu deinem Gemeinwohl-Beitrag", - "message": "„{message}“", - "toSeeAndAnswerMessage": "Um auf die Nachricht zu antworten, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“." - }, - "contribution": { - "toSeeContributionsAndMessages": "Um deine Gemeinwohl-Beiträge und dazugehörige Nachrichten zu sehen, gehe in deinem Gradido-Konto ins Menü „Schöpfen“ auf den Tab „Meine Beiträge“." - }, - "contributionChangedByModerator": { - "subject": "Dein Gemeinwohl-Beitrag wurde geändert", - "text": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} geändert und lautet jetzt „{contributionMemoUpdated}“", - "title": "Dein Gemeinwohl-Beitrag wurde geändert" - }, - "contributionConfirmed": { - "commonGoodContributionConfirmed": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde soeben von {senderFirstName} {senderLastName} bestätigt. Es wurden deinem Gradido-Konto {amountGDD} GDD gutgeschrieben.", - "subject": "Dein Gemeinwohl-Beitrag wurde bestätigt", - "title": "Dein Gemeinwohl-Beitrag wurde bestätigt" - }, - "contributionDeleted": { - "commonGoodContributionDeleted": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} gelöscht.", - "subject": "Dein Gemeinwohl-Beitrag wurde gelöscht", - "title": "Dein Gemeinwohl-Beitrag wurde gelöscht" - }, - "contributionDenied": { - "commonGoodContributionDenied": "dein Gemeinwohl-Beitrag „{contributionMemo}“ wurde von {senderFirstName} {senderLastName} abgelehnt.", - "subject": "Dein Gemeinwohl-Beitrag wurde abgelehnt", - "title": "Dein Gemeinwohl-Beitrag wurde abgelehnt" - }, - "footer": { - "contactOurSupport": "Bei weiteren Fragen kontaktiere bitte unseren Support.", - "imprint": "Impressum", - "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", - "imprintImageAlt": "Gradido-Akademie Logo", - "privacyPolicy": "Datenschutzerklärung", - "supportEmail": "support@gradido.net" - }, - "general": { - "amountGDD": "Betrag: {amountGDD} GDD", - "answerNow": "Jetzt antworten", - "completeRegistration": "Registrierung abschließen", - "contribution": "Gemeinwohl-Beitrag: {contributionMemo}", - "contributionDetails": "Beitragsdetails", - "detailsYouFindOnLinkToYourAccount": "Details zur Transaktion findest du in deinem Gradido-Konto.", - "helloName": "Hallo {firstName} {lastName},", - "linkValidity": "Der Link hat eine Gültigkeit von {hours} Stunden.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.", - "linkValidityWithMinutes": "Der Link hat eine Gültigkeit von {hours} Stunden und {minutes} Minuten.\nSollte die Gültigkeit des Links bereits abgelaufen sein, kannst du dir hier einen neuen Link schicken lassen.", - "message": "Nachricht", - "newLink": "Neuer Link", - "orCopyLink": "Oder kopiere den Link in dein Browserfenster.", - "pleaseDoNotReply": "Bitte antworte nicht auf diese E-Mail.", - "requestNewLink": "Neuen gültigen Link anfordern", - "reset": "zurücksetzen", - "sincerelyYours": "Liebe Grüße", - "toAccount": "Zum Konto", - "transactionDetails": "Transaktionsdetails", - "yourGradidoTeam": "dein Gradido-Team" - }, - "resetPassword": { - "pleaseClickLink": "Wenn du es warst, klicke bitte hier.", - "subject": "Passwort zurücksetzen", - "title": "Passwort zurücksetzen", - "youOrSomeoneResetPassword": "du oder jemand anderes, hast für dieses Konto ein Zurücksetzen des Passworts angefordert." - }, - "transactionLinkRedeemed": { - "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) hat soeben deinen Link eingelöst.", - "memo": "Nachricht: {transactionMemo}", - "subject": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst", - "title": "{senderFirstName} {senderLastName} hat deinen Gradido-Link eingelöst" - }, - "transactionReceived": { - "haveReceivedAmountGDDFrom": "du hast soeben {transactionAmount} GDD erhalten von {senderFirstName} {senderLastName}", - "subject": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet", - "replySubject": "Re: {senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet", - "title": "{senderFirstName} {senderLastName} hat dir {transactionAmount} Gradido gesendet" - } - }, - "general": { - "decimalSeparator": "," - } -} diff --git a/backend/src/locales/en.json b/backend/src/locales/en.json deleted file mode 100644 index fb90a0334..000000000 --- a/backend/src/locales/en.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "emails": { - "accountActivation": { - "activateAccount": "Activate account", - "emailRegistered": "Your email address has just been registered with Gradido.", - "pleaseClickLink": "Please click here to complete the registration and activate your Gradido account.", - "subject": "Email Verification", - "title": "Email Verification" - }, - "accountMultiRegistration": { - "contactSupport": "Contact support", - "emailExists": "However, an account already exists for your email address.", - "emailReused": "Your email address has just been used again to register an account with Gradido.", - "ifYouAreNotTheOne": "If you did not try to register again, please contact our support:", - "onForgottenPasswordClickLink": "If you have forgotten your password, please click here.", - "subject": "Try To Register Again With Your Email", - "title": "Try To Register Again With Your Email" - }, - "addedContributionMessage": { - "commonGoodContributionMessage": "You have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.", - "readMessage": "Read and reply to message", - "subject": "Message about your common good contribution", - "title": "Message about your common good contribution", - "message": "„{message}“", - "toSeeAndAnswerMessage": "To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." - }, - "contribution": { - "toSeeContributionsAndMessages": "To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." - }, - "contributionChangedByModerator": { - "subject": "Your common good contribution has been changed", - "text": "your common good contribution '{contributionMemo}' has just been changed by {senderFirstName} {senderLastName} and now reads as '{contributionMemoUpdated}'", - "title": "Your common good contribution has been changed" - }, - "contributionConfirmed": { - "commonGoodContributionConfirmed": "Your common good contribution “{contributionMemo}” has just been approved by {senderFirstName} {senderLastName}. Your Gradido account has been credited with {amountGDD} GDD.", - "subject": "Your contribution to the common good was confirmed", - "title": "Your contribution to the common good was confirmed" - }, - "contributionDeleted": { - "commonGoodContributionDeleted": "Your common good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.", - "subject": "Your common good contribution was deleted", - "title": "Your common good contribution was deleted" - }, - "contributionDenied": { - "commonGoodContributionDenied": "Your common good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.", - "subject": "Your common good contribution was rejected", - "title": "Your common good contribution was rejected" - }, - "footer": { - "contactOurSupport": "If you have any further questions, please contact our support.", - "imprint": "Impressum", - "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", - "imprintImageAlt": "Gradido-Akademie Logo", - "privacyPolicy": "Privacy Policy", - "supportEmail": "support@gradido.net" - }, - "general": { - "amountGDD": "Amount: {amountGDD} GDD", - "answerNow": "Reply", - "completeRegistration": "Complete registration", - "contribution": "Contribution: : {contributionMemo}", - "contributionDetails": "Contribution details", - "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account.", - "helloName": "Hello {firstName} {lastName},", - "linkValidity": "The link has a validity of {hours} hours.\nIf the validity of the link has already expired, you can have a new link sent to you here.", - "linkValidityWithMinutes": "The link has a validity of {hours} hours and {minutes} minutes.\nIf the validity of the link has already expired, you can have a new link sent to you here.", - "message": "Message", - "newLink": "New link", - "orCopyLink": "Or copy the link into your browser window.", - "pleaseDoNotReply": "Please do not reply to this email.", - "requestNewLink": "Request new valid link", - "reset": "reset", - "sincerelyYours": "Kind regards,", - "toAccount": "To account", - "transactionDetails": "Transaction details", - "yourGradidoTeam": "your Gradido team" - }, - "resetPassword": { - "pleaseClickLink": "If it was you, please click here.", - "subject": "Reset password", - "title": "Reset password", - "youOrSomeoneResetPassword": "You, or someone else, requested a password reset for this account." - }, - "transactionLinkRedeemed": { - "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) has just redeemed your link.", - "memo": "Message: {transactionMemo}", - "subject": "{senderFirstName} {senderLastName} has redeemed your Gradido link", - "title": "{senderFirstName} {senderLastName} has redeemed your Gradido link" - }, - "transactionReceived": { - "haveReceivedAmountGDDFrom": "You have just received {transactionAmount} GDD from {senderFirstName} {senderLastName}", - "replySubject": "RE: {senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", - "subject": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", - "title": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido" - } - }, - "general": { - "decimalSeparator": "." - } -} diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index 5f3bb02ef..eaa2ea5b4 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -1,4 +1,5 @@ import { CONFIG } from '@/config' +import { CONFIG as CORE_CONFIG } from 'core' import { schema } from '@/graphql/schema' import { elopageWebhook } from '@/webhook/elopage' import { gmsWebhook } from '@/webhook/gms' @@ -28,7 +29,6 @@ interface ServerDef { export const createServer = async ( apolloLogger: Logger, context: any = serverContext, - localization: i18n.I18n = i18n, ): Promise => { const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.createServer`) logger.debug('createServer...') @@ -73,9 +73,9 @@ export const createServer = async ( app.use(json()) // bodyparser urlencoded for elopage app.use(urlencoded({ extended: true })) - + // i18n - app.use(localization.init) + app.use(i18n.init) // Elopage Webhook @@ -100,7 +100,7 @@ export const createServer = async ( }) apollo.applyMiddleware({ app, path: '/' }) logger.info( - `running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CONFIG.EMAIL_TEST_MODUS} ...`, + `running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CORE_CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CORE_CONFIG.EMAIL_TEST_MODUS} ...`, ) logger.debug('createServer...successful') diff --git a/backend/src/server/localization.ts b/backend/src/server/localization.ts index 1e587104a..16f9d54b6 100644 --- a/backend/src/server/localization.ts +++ b/backend/src/server/localization.ts @@ -1,4 +1,3 @@ -import path from 'node:path' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import i18n from 'i18n' import { getLogger } from 'log4js' @@ -9,7 +8,7 @@ i18n.configure({ locales: ['en', 'de'], defaultLocale: 'en', retryInDefaultLocale: false, - directory: path.join(__dirname, '..', 'locales'), + staticCatalog: {'en': {}, 'de': {}}, // autoReload: true, // if this is activated the seeding hangs at the very end updateFiles: false, objectNotation: true, From 11147e81a91f5695e2f719a514d6d1a1e20bde3f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 14:47:34 +0100 Subject: [PATCH 142/226] move mails config to core --- backend/src/config/index.ts | 12 ------ backend/src/config/schema.ts | 83 +----------------------------------- 2 files changed, 1 insertion(+), 94 deletions(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index b583156b5..8af6e739a 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -64,22 +64,10 @@ const loginServer = { } const email = { - EMAIL: process.env.EMAIL === 'true', - EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true', - EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER ?? 'stage1@gradido.net', - EMAIL_USERNAME: process.env.EMAIL_USERNAME ?? '', - EMAIL_SENDER: process.env.EMAIL_SENDER ?? 'info@gradido.net', - EMAIL_PASSWORD: process.env.EMAIL_PASSWORD ?? '', - EMAIL_SMTP_HOST: process.env.EMAIL_SMTP_HOST ?? 'mailserver', - EMAIL_SMTP_PORT: Number(process.env.EMAIL_SMTP_PORT) || 1025, - - EMAIL_TLS: process.env.EMAIL_TLS !== 'false', EMAIL_LINK_VERIFICATION: COMMUNITY_URL + (process.env.EMAIL_LINK_VERIFICATION_PATH ?? '/checkEmail/'), EMAIL_LINK_SETPASSWORD: COMMUNITY_URL + (process.env.EMAIL_LINK_SETPASSWORD_PATH ?? '/reset-password/'), - EMAIL_LINK_FORGOTPASSWORD: - COMMUNITY_URL + (process.env.EMAIL_LINK_FORGOTPASSWORD_PATH ?? '/forgot-password'), EMAIL_LINK_OVERVIEW: COMMUNITY_URL + (process.env.EMAIL_LINK_OVERVIEW_PATH ?? '/overview'), // time in minutes a optin code is valid EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME diff --git a/backend/src/config/schema.ts b/backend/src/config/schema.ts index f4e6033ea..64871715c 100644 --- a/backend/src/config/schema.ts +++ b/backend/src/config/schema.ts @@ -83,76 +83,6 @@ export const schema = Joi.object({ .default('~/.gradido') .description('The home folder for the gradido dlt node server'), - EMAIL: Joi.boolean() - .default(false) - .description('Enable or disable email functionality') - .required(), - - EMAIL_TEST_MODUS: Joi.boolean() - .default(false) - .description('When enabled, all emails are sended to EMAIL_TEST_RECEIVER') - .optional(), - - EMAIL_TEST_RECEIVER: Joi.string() - .email() - .default('stage1@gradido.net') - .when('EMAIL_TEST_MODUS', { is: true, then: Joi.required() }) - .description('Email address used in test mode'), - - EMAIL_USERNAME: Joi.alternatives().conditional(Joi.ref('EMAIL'), { - is: true, - then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), { - is: 'development', - then: Joi.string() - .allow('') - .description('Username for SMTP authentication (optional in development)'), - otherwise: Joi.string() - .pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/) - .description('Valid SMTP username required in production') - .required(), - }), - otherwise: Joi.string().allow('').optional(), - }), - - EMAIL_SENDER: Joi.string() - .email() - .when('EMAIL', { is: true, then: Joi.required() }) - .default('info@gradido.net') - .description('Email address used as sender'), - - EMAIL_PASSWORD: Joi.alternatives().conditional(Joi.ref('EMAIL'), { - is: true, - then: Joi.alternatives().conditional(Joi.ref('NODE_ENV'), { - is: 'development', - then: Joi.string() - .allow('') - .description('Password for SMTP authentication (optional in development)'), - otherwise: Joi.string() - .min(8) - .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#]).{8,}$/) - .description( - 'Password must be at least 8 characters long, include uppercase and lowercase letters, a number, and a special character', - ) - .required(), - }), - otherwise: Joi.string().allow('').optional(), - }), - - EMAIL_SMTP_HOST: Joi.string() - .hostname() - .when('EMAIL', { is: true, then: Joi.required() }) - .default('mailserver') - .description('SMTP server hostname'), - - EMAIL_SMTP_PORT: Joi.number() - .integer() - .positive() - .when('EMAIL', { is: true, then: Joi.required() }) - .default(1025) - .description('SMTP server port'), - - EMAIL_TLS: Joi.boolean().default(true).description('Enable or disable TLS for SMTP').optional(), - EMAIL_LINK_VERIFICATION: Joi.string() .uri({ scheme: ['http', 'https'] }) .custom((value: string, helpers: Joi.CustomHelpers): string | Joi.ErrorReport => { @@ -175,17 +105,6 @@ export const schema = Joi.object({ .description('Email Verification link for set initial Password.') .required(), - EMAIL_LINK_FORGOTPASSWORD: Joi.string() - .uri({ scheme: ['http', 'https'] }) - .custom((value: string, helpers: Joi.CustomHelpers): string | Joi.ErrorReport => { - if (!value.startsWith(helpers.state.ancestors[0].COMMUNITY_URL)) { - return helpers.error('string.pattern.base', { value, communityUrl: COMMUNITY_URL }) - } - return value - }) - .description('Email Verification link for set new Password, when old Password was forgotten.') - .required(), - EMAIL_LINK_OVERVIEW: Joi.string() .uri({ scheme: ['http', 'https'] }) .custom((value: string, helpers: Joi.CustomHelpers): string | Joi.ErrorReport => { @@ -213,7 +132,7 @@ export const schema = Joi.object({ .description('Time in minutes before a new code can be requested') .required(), - FEDERATION_VALIDATE_COMMUNITY_TIMER: Joi.number() + FEDERATION_VALIDATE_COMMUNITY_TIMER: Joi.number() .integer() .min(1000) .default(60000) From 4e08a182e8902f1a55d7b1eda24ccb37dd941f0d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 16:41:29 +0100 Subject: [PATCH 143/226] update code for moved emails, fix bugs --- backend/.env.org | 77 ------- backend/package.json | 7 +- backend/scripts/sort_filter.jq | 13 -- backend/src/apis/gms/ExportUsers.ts | 4 +- .../resolver/CommunityResolver.test.ts | 3 +- .../ContributionMessageResolver.test.ts | 9 +- .../resolver/ContributionMessageResolver.ts | 2 +- .../resolver/ContributionResolver.test.ts | 22 +- .../graphql/resolver/ContributionResolver.ts | 7 +- .../graphql/resolver/EmailOptinCodes.test.ts | 3 +- .../resolver/KlicktippResolver.test.ts | 3 +- .../resolver/TransactionResolver.test.ts | 3 +- .../graphql/resolver/TransactionResolver.ts | 18 +- .../src/graphql/resolver/UserResolver.test.ts | 9 +- backend/src/graphql/resolver/UserResolver.ts | 17 +- .../src/graphql/resolver/semaphore.test.ts | 3 +- backend/src/seeds/index.ts | 3 +- backend/src/server/localization.ts | 5 +- backend/test/helpers.ts | 6 +- backend/test/testSetup.ts | 22 +- backend/tsconfig.json | 5 +- backend/turbo.json | 2 - bun.lock | 133 +++++------ core/esbuild.config.ts | 6 +- core/package.json | 2 + {backend => core}/scripts/sort.sh | 4 +- core/src/emails/locales/en.json | 206 +++++++++--------- core/src/emails/sendEmailTranslated.ts | 11 +- core/turbo.json | 13 ++ 29 files changed, 269 insertions(+), 349 deletions(-) delete mode 100644 backend/.env.org delete mode 100644 backend/scripts/sort_filter.jq rename {backend => core}/scripts/sort.sh (83%) create mode 100644 core/turbo.json diff --git a/backend/.env.org b/backend/.env.org deleted file mode 100644 index 2267fdc50..000000000 --- a/backend/.env.org +++ /dev/null @@ -1,77 +0,0 @@ -# Server -PORT=4000 -JWT_SECRET=secret123 -JWT_EXPIRES_IN=10m -GRAPHIQL=false -GDT_API_URL=https://gdt.gradido.net - -# Database -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_community -TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log - -# Klicktipp -KLICKTIPP=false -KLICKTTIPP_API_URL=https://api.klicktipp.com -KLICKTIPP_USER=gradido_test -KLICKTIPP_PASSWORD=secret321 -KLICKTIPP_APIKEY_DE=SomeFakeKeyDE -KLICKTIPP_APIKEY_EN=SomeFakeKeyEN - -# DltConnector -DLT_CONNECTOR=true -DLT_CONNECTOR_URL=http://localhost:6010 - -# Community -COMMUNITY_NAME=Gradido Entwicklung -COMMUNITY_URL=http://localhost -COMMUNITY_REGISTER_PATH=/register -COMMUNITY_REDEEM_PATH=/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_PATH=/redeem/CL-{code} -COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. -COMMUNITY_SUPPORT_MAIL=support@supportmail.com - -# Login Server -LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a - -# EMail -EMAIL=false -EMAIL_TEST_MODUS=false -EMAIL_TEST_RECEIVER=stage1@gradido.net -EMAIL_USERNAME=gradido_email -EMAIL_SENDER=info@gradido.net -EMAIL_PASSWORD=xxx -EMAIL_SMTP_HOST=gmail.com -EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION_PATH=/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD_PATH=/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD_PATH=/forgot-password -EMAIL_LINK_OVERVIEW_PATH=/overview -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - -# Webhook -WEBHOOK_ELOPAGE_SECRET=secret - -# SET LOG LEVEL AS NEEDED IN YOUR .ENV -# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal -LOG_LEVEL=INFO - -# Federation -FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 - -# GMS -# GMS_ACTIVE=true -# Coordinates of Illuminz test instance -#GMS_API_URL=http://54.176.169.179:3071 -GMS_API_URL=http://localhost:4044 -GMS_DASHBOARD_URL=http://localhost:8080 - -# HUMHUB -HUMHUB_ACTIVE=true -HUMHUB_API_URL=https://community-test.gradido.net -HUMHUB_JWT_KEY=GwdkIKi-rkRS0mXC4Cg3MYc3ktZh89VFmntDpNKET_dUfcIdjL_957F3nCv3brNtDfbbV81NViKaktUsfExrkH diff --git a/backend/package.json b/backend/package.json index d758c5518..0a1bab487 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,7 @@ "author": "Gradido Academy - https://www.gradido.net", "main": "src/index.ts", "scripts": { - "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp src/emails/templates build/templates && mkdirp locales/ && ncp src/locales locales", + "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/src/emails/templates build/templates", "dev": "cross-env TZ=UTC nodemon -w src --ext ts,pug,json,css -r tsconfig-paths/register src/index.ts", "test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --runInBand --forceExit --detectOpenHandles", "test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --coverage --runInBand --forceExit --detectOpenHandles", @@ -19,8 +19,6 @@ "lint": "biome check --error-on-warnings .", "lint:fix": "biome check --error-on-warnings . --write", "lint:fix:unsafe": "biome check --fix --unsafe", - "locales": "scripts/sort.sh", - "locales:fix": "scripts/sort.sh --fix", "start": "cross-env TZ=UTC node build/index.js", "typecheck": "tsc --noEmit", "clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo" @@ -49,7 +47,6 @@ "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -83,11 +80,9 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "^6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", - "pug": "^3.0.2", "random-bigint": "^0.0.1", "reflect-metadata": "^0.1.13", "regenerator-runtime": "^0.14.1", diff --git a/backend/scripts/sort_filter.jq b/backend/scripts/sort_filter.jq deleted file mode 100644 index 9d108f8f0..000000000 --- a/backend/scripts/sort_filter.jq +++ /dev/null @@ -1,13 +0,0 @@ -def walk(f): - . as $in - | if type == "object" then - reduce keys_unsorted[] as $key - ( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f - elif type == "array" then map( walk(f) ) | f - else f - end; - -def keys_sort_by(f): - to_entries | sort_by(.key|f ) | from_entries; - -walk(if type == "object" then keys_sort_by(ascii_upcase) else . end) \ No newline at end of file diff --git a/backend/src/apis/gms/ExportUsers.ts b/backend/src/apis/gms/ExportUsers.ts index 03cc92fa4..5c5cb72d8 100644 --- a/backend/src/apis/gms/ExportUsers.ts +++ b/backend/src/apis/gms/ExportUsers.ts @@ -4,7 +4,7 @@ import { User as DbUser } from 'database' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' // import { createGmsUser } from '@/apis/gms/GmsClient' // import { GmsUser } from '@/apis/gms/model/GmsUser' -import { CONFIG } from '@/config' +import { CONFIG as CORE_CONFIG } from 'core' import { sendUserToGms } from '@/graphql/resolver/util/sendUserToGms' import { LogError } from '@/server/LogError' import { initLogging } from '@/server/logger' @@ -13,7 +13,7 @@ import { getLogger } from 'log4js' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.gms.ExportUsers`) -CONFIG.EMAIL = false +CORE_CONFIG.EMAIL = false // use force to copy over all user even if gmsRegistered is set to true const forceMode = process.argv.includes('--force') diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 57173c9d1..0f48d356b 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -5,7 +5,6 @@ import { DataSource } from 'typeorm' import { v4 as uuidv4 } from 'uuid' import { cleanDB, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' import { userFactory } from '@/seeds/factory/user' import { login, updateHomeCommunityQuery } from '@/seeds/graphql/mutations' @@ -43,7 +42,7 @@ const peterLoginData = { } beforeAll(async () => { - testEnv = await testEnvironment(getLogger('apollo'), localization) + testEnv = await testEnvironment(getLogger('apollo')) mutate = testEnv.mutate query = testEnv.query con = testEnv.con diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 962b77766..d29bf5235 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -5,10 +5,9 @@ import { DataSource } from 'typeorm' import { ContributionStatus } from '@enum/ContributionStatus' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants' +import { sendAddedContributionMessageEmail } from 'core' import { EventType } from '@/event/Events' import { userFactory } from '@/seeds/factory/user' import { @@ -30,8 +29,8 @@ const interactionLogger = getLogger( ) jest.mock('@/password/EncryptorUtils') -jest.mock('@/emails/sendEmailVariants', () => { - const originalModule = jest.requireActual('@/emails/sendEmailVariants') +jest.mock('core', () => { + const originalModule = jest.requireActual('core') return { __esModule: true, ...originalModule, @@ -51,7 +50,7 @@ let testEnv: { let result: any beforeAll(async () => { - testEnv = await testEnvironment(logger, localization) + testEnv = await testEnvironment(logger) mutate = testEnv.mutate con = testEnv.con await cleanDB() diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 8ddf782b0..5926a1bc4 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -14,7 +14,7 @@ import { Order } from '@enum/Order' import { ContributionMessage, ContributionMessageListResult } from '@model/ContributionMessage' import { RIGHTS } from '@/auth/RIGHTS' -import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants' +import { sendAddedContributionMessageEmail } from 'core' import { EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE, EVENT_CONTRIBUTION_MESSAGE_CREATE, diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 6dee20592..fd31a5275 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -14,14 +14,13 @@ import { resetToken, testEnvironment, } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { sendContributionConfirmedEmail, sendContributionDeletedEmail, sendContributionDeniedEmail, -} from '@/emails/sendEmailVariants' +} from 'core' import { EventType } from '@/event/Events' import { creations } from '@/seeds/creation/index' import { creationFactory } from '@/seeds/factory/creation' @@ -54,7 +53,22 @@ import { getFirstDayOfPreviousNMonth } from 'core' import { getLogger } from 'config-schema/test/testSetup' import { getLogger as originalGetLogger } from 'log4js' -jest.mock('@/emails/sendEmailVariants') +jest.mock('core', () => { + const originalModule = jest.requireActual('core') + return { + __esModule: true, + ...originalModule, + sendContributionDeniedEmail: jest.fn((a) => + originalModule.sendContributionDeniedEmail(a), + ), + sendContributionConfirmedEmail: jest.fn((a) => + originalModule.sendContributionConfirmedEmail(a), + ), + sendContributionDeletedEmail: jest.fn((a) => + originalModule.sendContributionDeletedEmail(a), + ), + } +}) jest.mock('@/password/EncryptorUtils') const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) @@ -77,7 +91,7 @@ let contributionToDelete: any let bibiCreatedContribution: Contribution beforeAll(async () => { - testEnv = await testEnvironment(originalGetLogger('apollo'), localization) + testEnv = await testEnvironment(originalGetLogger('apollo')) mutate = testEnv.mutate query = testEnv.query con = testEnv.con diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index ac06f012e..180c22cfb 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -21,15 +21,15 @@ import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { OpenCreation } from '@model/OpenCreation' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { TransactionTypeId } from 'core' - import { RIGHTS } from '@/auth/RIGHTS' import { + fullName, sendContributionChangedByModeratorEmail, sendContributionConfirmedEmail, sendContributionDeletedEmail, sendContributionDeniedEmail, -} from '@/emails/sendEmailVariants' + TransactionTypeId +} from 'core' import { EVENT_ADMIN_CONTRIBUTION_CONFIRM, EVENT_ADMIN_CONTRIBUTION_CREATE, @@ -44,7 +44,6 @@ import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUncon import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' import { TRANSACTIONS_LOCK } from 'database' -import { fullName } from 'core' import { calculateDecay, Decay } from 'shared' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' diff --git a/backend/src/graphql/resolver/EmailOptinCodes.test.ts b/backend/src/graphql/resolver/EmailOptinCodes.test.ts index b916d23b6..18114dbb2 100644 --- a/backend/src/graphql/resolver/EmailOptinCodes.test.ts +++ b/backend/src/graphql/resolver/EmailOptinCodes.test.ts @@ -5,6 +5,7 @@ import { DataSource } from 'typeorm' import { cleanDB, testEnvironment } from '@test/helpers' +import { CONFIG as CORE_CONFIG } from 'core' import { CONFIG } from '@/config' import { writeHomeCommunityEntry } from '@/seeds/community' import { createUser, forgotPassword, setPassword } from '@/seeds/graphql/mutations' @@ -21,7 +22,7 @@ let testEnv: { CONFIG.EMAIL_CODE_VALID_TIME = 1440 CONFIG.EMAIL_CODE_REQUEST_TIME = 10 -CONFIG.EMAIL = false +CORE_CONFIG.EMAIL = false beforeAll(async () => { testEnv = await testEnvironment() diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index f3ac85ef4..1c285d440 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -2,7 +2,6 @@ import { Event as DbEvent, UserContact } from 'database' import { GraphQLError } from 'graphql' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' import { getLogger } from 'config-schema/test/testSetup' import { EventType } from '@/event/Events' @@ -20,7 +19,7 @@ let mutate: any let con: any beforeAll(async () => { - testEnv = await testEnvironment(logger, localization) + testEnv = await testEnvironment(logger) mutate = testEnv.mutate con = testEnv.con await cleanDB() diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index a134ca84b..774502b28 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -34,12 +34,13 @@ import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' import { getLogger } from 'config-schema/test/testSetup' import { CONFIG } from '@/config' +import { CONFIG as CORE_CONFIG} from 'core' jest.mock('@/password/EncryptorUtils') const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) CONFIG.DLT_CONNECTOR = false -CONFIG.EMAIL = false +CORE_CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 359e69b45..923971743 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -1,14 +1,11 @@ import { AppDatabase, countOpenPendingTransactions, - Community as DbCommunity, DltTransaction as DbDltTransaction, Transaction as dbTransaction, TransactionLink as dbTransactionLink, User as dbUser, findUserByIdentifier, - TransactionLoggingView, - UserLoggingView } from 'database' import { Decimal } from 'decimal.js-light' import { Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' @@ -20,21 +17,22 @@ import { Order } from '@enum/Order' import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { User } from '@model/User' -import { processXComCompleteTransaction, TransactionTypeId } from 'core' - +import { + fullName, + processXComCompleteTransaction, + sendTransactionLinkRedeemedEmail, + sendTransactionReceivedEmail, + TransactionTypeId +} from 'core' import { RIGHTS } from '@/auth/RIGHTS' import { CONFIG } from '@/config' import { - sendTransactionLinkRedeemedEmail, - sendTransactionReceivedEmail, -} from '@/emails/sendEmailVariants' -import { EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Events' + EVENT_TRANSACTION_RECEIVE, EVENT_TRANSACTION_SEND } from '@/event/Events' import { LogError } from '@/server/LogError' import { Context, getUser } from '@/server/context' import { communityUser } from '@/util/communityUser' import { calculateBalance } from '@/util/validate' import { virtualDecayTransaction, virtualLinkTransaction } from '@/util/virtualTransactions' -import { fullName } from 'core' import { TRANSACTIONS_LOCK } from 'database' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 8b4faa443..d5bad3bc8 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -20,7 +20,6 @@ import { UserContactType } from '@enum/UserContactType' import { ContributionLink } from '@model/ContributionLink' import { Location } from '@model/Location' import { cleanDB, headerPushMock, resetToken, testEnvironment } from '@test/helpers' -import { i18n as localization } from '@test/testSetup' import { subscribe } from '@/apis/KlicktippController' import { CONFIG } from '@/config' @@ -28,7 +27,7 @@ import { sendAccountActivationEmail, sendAccountMultiRegistrationEmail, sendResetPasswordEmail, -} from '@/emails/sendEmailVariants' +} from 'core' import { EventType } from '@/event/Events' import { PublishNameType } from '@/graphql/enum/PublishNameType' import { SecretKeyCryptographyCreateKey } from '@/password/EncryptorUtils' @@ -74,8 +73,8 @@ import { Location2Point } from './util/Location2Point' jest.mock('@/apis/humhub/HumHubClient') jest.mock('@/password/EncryptorUtils') -jest.mock('@/emails/sendEmailVariants', () => { - const originalModule = jest.requireActual('@/emails/sendEmailVariants') +jest.mock('core', () => { + const originalModule = jest.requireActual('core') return { __esModule: true, ...originalModule, @@ -112,7 +111,7 @@ let testEnv: { } beforeAll(async () => { - testEnv = await testEnvironment(getLogger('apollo'), localization) + testEnv = await testEnvironment(getLogger('apollo')) mutate = testEnv.mutate query = testEnv.query con = testEnv.con diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 70b1642a8..4a2ca85ca 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -10,7 +10,6 @@ import { findUserByIdentifier } from 'database' import { GraphQLResolveInfo } from 'graphql' -import i18n from 'i18n' import { Arg, Args, @@ -57,11 +56,6 @@ import { encode } from '@/auth/JWT' import { RIGHTS } from '@/auth/RIGHTS' import { CONFIG } from '@/config' import { PublishNameLogic } from '@/data/PublishName.logic' -import { - sendAccountActivationEmail, - sendAccountMultiRegistrationEmail, - sendResetPasswordEmail, -} from '@/emails/sendEmailVariants' import { EVENT_ADMIN_USER_DELETE, EVENT_ADMIN_USER_ROLE_SET, @@ -85,8 +79,12 @@ import { Context, getClientTimezoneOffset, getUser } from '@/server/context' import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' import { durationInMinutesFromDates, getTimeDurationObject, printTimeDuration } from '@/util/time' -import { delay } from 'core' - +import { + delay, + sendAccountActivationEmail, + sendAccountMultiRegistrationEmail, + sendResetPasswordEmail, +} from 'core' import random from 'random-bigint' import { randombytes_random } from 'sodium-native' @@ -233,7 +231,6 @@ export class UserResolver { logger.debug('validation of login credentials successful...') const user = new User(dbUser) - i18n.setLocale(user.language) // Elopage Status & Stored PublisherId user.hasElopage = await this.hasElopage({ ...context, user: dbUser }) @@ -322,7 +319,6 @@ export class UserResolver { if (!language || !isLanguage(language)) { language = DEFAULT_LANGUAGE } - i18n.setLocale(language) // check if user with email still exists? email = email.trim().toLowerCase() @@ -764,7 +760,6 @@ export class UserResolver { throw new LogError('Given language is not a valid language or not supported') } user.language = language - i18n.setLocale(language) updated = true } diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index d0bf08b7c..d88ed1857 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -22,12 +22,13 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { CONFIG } from '@/config' +import { CONFIG as CORE_CONFIG } from 'core' import { TRANSACTIONS_LOCK } from 'database' jest.mock('@/password/EncryptorUtils') CONFIG.DLT_CONNECTOR = false -CONFIG.EMAIL = false +CORE_CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] let con: DataSource diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 451f671ac..3a1504262 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -3,6 +3,7 @@ import { entities } from 'database' import { datatype, internet, name } from 'faker' import { CONFIG } from '@/config' +import { CONFIG as CORE_CONFIG } from 'core' import { createServer } from '@/server/createServer' import { initLogging } from '@/server/logger' @@ -17,7 +18,7 @@ import { userFactory } from './factory/user' import { transactionLinks } from './transactionLink/index' import { users } from './users/index' -CONFIG.EMAIL = false +CORE_CONFIG.EMAIL = false const logger = getLogger('seed') const context = { diff --git a/backend/src/server/localization.ts b/backend/src/server/localization.ts index 16f9d54b6..2332f0eaf 100644 --- a/backend/src/server/localization.ts +++ b/backend/src/server/localization.ts @@ -8,7 +8,10 @@ i18n.configure({ locales: ['en', 'de'], defaultLocale: 'en', retryInDefaultLocale: false, - staticCatalog: {'en': {}, 'de': {}}, + staticCatalog: { + en: { general: { decimalSeparator: "." } }, + de: { general: { decimalSeparator: "," } }, + }, // autoReload: true, // if this is activated the seeding hangs at the very end updateFiles: false, objectNotation: true, diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index c7f533931..7001e3067 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -3,8 +3,6 @@ import { entities } from 'database' import { createServer } from '@/server/createServer' -import { i18n } from './testSetup' - import { getLogger } from 'log4js' export const headerPushMock = jest.fn((t) => { @@ -29,8 +27,8 @@ export const cleanDB = async () => { } } -export const testEnvironment = async (testLogger = getLogger('apollo'), testI18n = i18n) => { - const server = await createServer( testLogger, context, testI18n) +export const testEnvironment = async (testLogger = getLogger('apollo')) => { + const server = await createServer( testLogger, context) const con = server.con const testClient = createTestClient(server.apollo) const mutate = testClient.mutate diff --git a/backend/test/testSetup.ts b/backend/test/testSetup.ts index c010ff705..6a009e652 100644 --- a/backend/test/testSetup.ts +++ b/backend/test/testSetup.ts @@ -1,27 +1,13 @@ import 'openai/shims/node' import { CONFIG } from '@/config' -import { i18n } from '@/server/localization' +import { CONFIG as CORE_CONFIG } from 'core' import { getLogger, printLogs, clearLogs } from 'config-schema/test/testSetup' -CONFIG.EMAIL = true -CONFIG.EMAIL_TEST_MODUS = false +CORE_CONFIG.EMAIL = true +CORE_CONFIG.EMAIL_TEST_MODUS = false CONFIG.HUMHUB_ACTIVE = false CONFIG.GMS_ACTIVE = false jest.setTimeout(1000000) -jest.mock('@/server/localization', () => { - const originalModule = jest.requireActual('@/server/localization') - return { - __esModule: true, - ...originalModule, - i18n: { - init: jest.fn(), - // configure: jest.fn(), - // __: jest.fn(), - // setLocale: jest.fn(), - }, - } -}) - -export { i18n, getLogger, printLogs, clearLogs as cleanLogs } +export { getLogger, printLogs, clearLogs as cleanLogs } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 2152f4b79..d330e2b81 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -63,7 +63,7 @@ "typeRoots": [ /* List of folders to include type definitions from. */ "@types", "node_modules/@types", - "../node_modules/@types" + "../node_modules/@types", ], // "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. */ @@ -86,6 +86,9 @@ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ }, + "include": [ + "../core/src/types", + ], "ts-node": { "swc": true } diff --git a/backend/turbo.json b/backend/turbo.json index 822b2765f..399bfa6ba 100644 --- a/backend/turbo.json +++ b/backend/turbo.json @@ -8,10 +8,8 @@ "locales": {}, "locales:fix": {}, "lint": { - "dependsOn": ["locales"] }, "lint:fix": { - "dependsOn": ["locales:fix"] }, "test": { "dependsOn": ["database#up:backend_test", "^build"] diff --git a/bun.lock b/bun.lock index 0f2ac4c20..9b449354c 100644 --- a/bun.lock +++ b/bun.lock @@ -109,7 +109,6 @@ "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^17.0.21", - "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "@types/source-map-support": "^0.5.10", "@types/uuid": "^8.3.4", @@ -143,11 +142,9 @@ "log4js": "^6.7.1", "mkdirp": "^3.0.1", "ncp": "^2.0.0", - "nodemailer": "^6.6.5", "nodemon": "^2.0.7", "openai": "^4.87.3", "prettier": "^3.5.3", - "pug": "^3.0.2", "random-bigint": "^0.0.1", "reflect-metadata": "^0.1.13", "regenerator-runtime": "^0.14.1", @@ -188,20 +185,25 @@ "version": "2.7.1", "dependencies": { "database": "*", + "email-templates": "^10.0.1", "esbuild": "^0.25.2", "i18n": "^0.15.1", "joi": "^17.13.3", "jose": "^4.14.4", "log4js": "^6.9.1", + "nodemailer": "^6.6.5", + "pug": "^3.0.2", "shared": "*", "sodium-native": "^3.4.1", "zod": "^3.25.61", }, "devDependencies": { "@biomejs/biome": "2.0.0", + "@types/email-templates": "^10.0.4", "@types/i18n": "^0.13.4", "@types/minimatch": "6.0.0", "@types/node": "^17.0.21", + "@types/nodemailer": "^6.4.4", "@types/sodium-native": "^2.3.5", "config-schema": "*", "decimal.js-light": "^2.5.1", @@ -288,6 +290,7 @@ "version": "2.7.1", "dependencies": { "cross-env": "^7.0.3", + "email-templates": "^10.0.1", "sodium-native": "^3.4.1", }, "devDependencies": { @@ -325,6 +328,8 @@ "joi": "17.13.3", "lodash.clonedeep": "^4.5.0", "log4js": "^6.7.1", + "mkdirp": "^3.0.1", + "ncp": "^2.0.0", "nodemon": "^2.0.7", "prettier": "^3.5.3", "reflect-metadata": "^0.1.13", @@ -485,53 +490,55 @@ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], - "@aws-sdk/client-ses": ["@aws-sdk/client-ses@3.913.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.911.0", "@aws-sdk/credential-provider-node": "3.913.0", "@aws-sdk/middleware-host-header": "3.910.0", "@aws-sdk/middleware-logger": "3.910.0", "@aws-sdk/middleware-recursion-detection": "3.910.0", "@aws-sdk/middleware-user-agent": "3.911.0", "@aws-sdk/region-config-resolver": "3.910.0", "@aws-sdk/types": "3.910.0", "@aws-sdk/util-endpoints": "3.910.0", "@aws-sdk/util-user-agent-browser": "3.910.0", "@aws-sdk/util-user-agent-node": "3.911.0", "@smithy/config-resolver": "^4.3.2", "@smithy/core": "^3.16.1", "@smithy/fetch-http-handler": "^5.3.3", "@smithy/hash-node": "^4.2.2", "@smithy/invalid-dependency": "^4.2.2", "@smithy/middleware-content-length": "^4.2.2", "@smithy/middleware-endpoint": "^4.3.3", "@smithy/middleware-retry": "^4.4.3", "@smithy/middleware-serde": "^4.2.2", "@smithy/middleware-stack": "^4.2.2", "@smithy/node-config-provider": "^4.3.2", "@smithy/node-http-handler": "^4.4.1", "@smithy/protocol-http": "^5.3.2", "@smithy/smithy-client": "^4.8.1", "@smithy/types": "^4.7.1", "@smithy/url-parser": "^4.2.2", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.2", "@smithy/util-defaults-mode-node": "^4.2.3", "@smithy/util-endpoints": "^3.2.2", "@smithy/util-middleware": "^4.2.2", "@smithy/util-retry": "^4.2.2", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-jUF1mN+webeAgkNXS/tl6KpJyUbsAWxQGsQgsWoHwaNCSnxMDBEyPmgBnzbqf2CrybIa7zmzaqCO0z6FgKeZRg=="], + "@aws-sdk/client-ses": ["@aws-sdk/client-ses@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/credential-provider-node": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-2toHYwRkcYGasPHYGwOwaIAa2Api/uFhmL3px0Tyt4bne2ilqhSwq+6a/0UVMd8JYwWaLMJolTbWKFt2jUlmGg=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.911.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.911.0", "@aws-sdk/middleware-host-header": "3.910.0", "@aws-sdk/middleware-logger": "3.910.0", "@aws-sdk/middleware-recursion-detection": "3.910.0", "@aws-sdk/middleware-user-agent": "3.911.0", "@aws-sdk/region-config-resolver": "3.910.0", "@aws-sdk/types": "3.910.0", "@aws-sdk/util-endpoints": "3.910.0", "@aws-sdk/util-user-agent-browser": "3.910.0", "@aws-sdk/util-user-agent-node": "3.911.0", "@smithy/config-resolver": "^4.3.2", "@smithy/core": "^3.16.1", "@smithy/fetch-http-handler": "^5.3.3", "@smithy/hash-node": "^4.2.2", "@smithy/invalid-dependency": "^4.2.2", "@smithy/middleware-content-length": "^4.2.2", "@smithy/middleware-endpoint": "^4.3.3", "@smithy/middleware-retry": "^4.4.3", "@smithy/middleware-serde": "^4.2.2", "@smithy/middleware-stack": "^4.2.2", "@smithy/node-config-provider": "^4.3.2", "@smithy/node-http-handler": "^4.4.1", "@smithy/protocol-http": "^5.3.2", "@smithy/smithy-client": "^4.8.1", "@smithy/types": "^4.7.1", "@smithy/url-parser": "^4.2.2", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.2", "@smithy/util-defaults-mode-node": "^4.2.3", "@smithy/util-endpoints": "^3.2.2", "@smithy/util-middleware": "^4.2.2", "@smithy/util-retry": "^4.2.2", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-N9QAeMvN3D1ZyKXkQp4aUgC4wUMuA5E1HuVCkajc0bq1pnH4PIke36YlrDGGREqPlyLFrXCkws2gbL5p23vtlg=="], + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-0G73S2cDqYwJVvqL08eakj79MZG2QRaB56Ul8/Ps9oQxllr7DMI1IQ/N3j3xjxgpq/U36pkoFZ8aK1n7Sbr3IQ=="], - "@aws-sdk/core": ["@aws-sdk/core@3.911.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@aws-sdk/xml-builder": "3.911.0", "@smithy/core": "^3.16.1", "@smithy/node-config-provider": "^4.3.2", "@smithy/property-provider": "^4.2.2", "@smithy/protocol-http": "^5.3.2", "@smithy/signature-v4": "^5.3.2", "@smithy/smithy-client": "^4.8.1", "@smithy/types": "^4.7.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.2", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k4QG9A+UCq/qlDJFmjozo6R0eXXfe++/KnCDMmajehIE9kh+b/5DqlGvAmbl9w4e92LOtrY6/DN3mIX1xs4sXw=="], + "@aws-sdk/core": ["@aws-sdk/core@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eGJ2ySUMvgtOziHhDRDLCrj473RJoL4J1vPjVM3NrKC/fF3/LoHjkut8AAnKmrW6a2uTzNKubigw8dEnpmpERw=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/property-provider": "^4.2.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-6FWRwWn3LUZzLhqBXB+TPMW2ijCWUqGICSw8bVakEdODrvbiv1RT/MVUayzFwz/ek6e6NKZn6DbSWzx07N9Hjw=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-dKajFuaugEA5i9gCKzOaVy9uTeZcApE+7Z5wdcZ6j40523fY1a56khDAUYkCfwqa7sHci4ccmxBkAo+fW1RChA=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/fetch-http-handler": "^5.3.3", "@smithy/node-http-handler": "^4.4.1", "@smithy/property-provider": "^4.2.2", "@smithy/protocol-http": "^5.3.2", "@smithy/smithy-client": "^4.8.1", "@smithy/types": "^4.7.1", "@smithy/util-stream": "^4.5.2", "tslib": "^2.6.2" } }, "sha512-xUlwKmIUW2fWP/eM3nF5u4CyLtOtyohlhGJ5jdsJokr3MrQ7w0tDITO43C9IhCn+28D5UbaiWnKw5ntkw7aVfA=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-5FguODLXG1tWx/x8fBxH+GVrk7Hey2LbXV5h9SFzYCx/2h50URBm0+9hndg0Rd23+xzYe14F6SI9HA9c1sPnjg=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.913.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/credential-provider-env": "3.911.0", "@aws-sdk/credential-provider-http": "3.911.0", "@aws-sdk/credential-provider-process": "3.911.0", "@aws-sdk/credential-provider-sso": "3.911.0", "@aws-sdk/credential-provider-web-identity": "3.911.0", "@aws-sdk/nested-clients": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/credential-provider-imds": "^4.2.2", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-iR4c4NQ1OSRKQi0SxzpwD+wP1fCy+QNKtEyCajuVlD0pvmoIHdrm5THK9e+2/7/SsQDRhOXHJfLGxHapD74WJw=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/credential-provider-env": "3.936.0", "@aws-sdk/credential-provider-http": "3.936.0", "@aws-sdk/credential-provider-login": "3.936.0", "@aws-sdk/credential-provider-process": "3.936.0", "@aws-sdk/credential-provider-sso": "3.936.0", "@aws-sdk/credential-provider-web-identity": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-TbUv56ERQQujoHcLMcfL0Q6bVZfYF83gu/TjHkVkdSlHPOIKaG/mhE2XZSQzXv1cud6LlgeBbfzVAxJ+HPpffg=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.913.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.911.0", "@aws-sdk/credential-provider-http": "3.911.0", "@aws-sdk/credential-provider-ini": "3.913.0", "@aws-sdk/credential-provider-process": "3.911.0", "@aws-sdk/credential-provider-sso": "3.911.0", "@aws-sdk/credential-provider-web-identity": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/credential-provider-imds": "^4.2.2", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-HQPLkKDxS83Q/nZKqg9bq4igWzYQeOMqhpx5LYs4u1GwsKeCsYrrfz12Iu4IHNWPp9EnGLcmdfbfYuqZGrsaSQ=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8DVrdRqPyUU66gfV7VZNToh56ZuO5D6agWrkLQE/xbLJOm2RbeRgh6buz7CqV8ipRd6m+zCl9mM4F3osQLZn8Q=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-mKshhV5jRQffZjbK9x7bs+uC2IsYKfpzYaBamFsEov3xtARCpOiKaIlM8gYKFEbHT2M+1R3rYYlhhl9ndVWS2g=="], + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.936.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.936.0", "@aws-sdk/credential-provider-http": "3.936.0", "@aws-sdk/credential-provider-ini": "3.936.0", "@aws-sdk/credential-provider-process": "3.936.0", "@aws-sdk/credential-provider-sso": "3.936.0", "@aws-sdk/credential-provider-web-identity": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-rk/2PCtxX9xDsQW8p5Yjoca3StqmQcSfkmD7nQ61AqAHL1YgpSQWqHE+HjfGGiHDYKG7PvE33Ku2GyA7lEIJAw=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.911.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.911.0", "@aws-sdk/core": "3.911.0", "@aws-sdk/token-providers": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-JAxd4uWe0Zc9tk6+N0cVxe9XtJVcOx6Ms0k933ZU9QbuRMH6xti/wnZxp/IvGIWIDzf5fhqiGyw5MSyDeI5b1w=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GpA4AcHb96KQK2PSPUyvChvrsEKiLhQ5NWjeef2IZ3Jc8JoosiedYqp6yhZR+S8cTysuvx56WyJIJc8y8OTrLA=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/nested-clients": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-urIbXWWG+cm54RwwTFQuRwPH0WPsMFSDF2/H9qO2J2fKoHRURuyblFCyYG3aVKZGvFBhOizJYexf5+5w3CJKBw=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.936.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.936.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/token-providers": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wHlEAJJvtnSyxTfNhN98JcU4taA1ED2JvuI2eePgawqBwS/Tzi0mhED1lvNIaWOkjfLd+nHALwszGrtJwEq4yQ=="], - "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@smithy/protocol-http": "^5.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-F9Lqeu80/aTM6S/izZ8RtwSmjfhWjIuxX61LX+/9mxJyEkgaECRxv0chsLQsLHJumkGnXRy/eIyMLBhcTPF5vg=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-v3qHAuoODkoRXsAF4RG+ZVO6q2P9yYBT4GMpMEfU9wXVNn7AIfwZgTwzSUfnjNiGva5BKleWVpRpJ9DeuLFbUg=="], - "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-3LJyyfs1USvRuRDla1pGlzGRtXJBXD1zC9F+eE9Iz/V5nkmhyv52A017CvKWmYoR0DM9dzjLyPOI0BSSppEaTw=="], + "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@aws/lambda-invoke-store": "^0.0.1", "@smithy/protocol-http": "^5.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-m/oLz0EoCy+WoIVBnXRXJ4AtGpdl0kPE7U+VH9TsuUzHgxY1Re/176Q1HWLBRVlz4gr++lNsgsMWEC+VnAwMpw=="], + "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/types": "3.910.0", "@aws-sdk/util-endpoints": "3.910.0", "@smithy/core": "^3.16.1", "@smithy/protocol-http": "^5.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-rY3LvGvgY/UI0nmt5f4DRzjEh8135A2TeHcva1bgOmVfOI4vkkGfA20sNRqerOkSO6hPbkxJapO50UJHFzmmyA=="], + "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.911.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.911.0", "@aws-sdk/middleware-host-header": "3.910.0", "@aws-sdk/middleware-logger": "3.910.0", "@aws-sdk/middleware-recursion-detection": "3.910.0", "@aws-sdk/middleware-user-agent": "3.911.0", "@aws-sdk/region-config-resolver": "3.910.0", "@aws-sdk/types": "3.910.0", "@aws-sdk/util-endpoints": "3.910.0", "@aws-sdk/util-user-agent-browser": "3.910.0", "@aws-sdk/util-user-agent-node": "3.911.0", "@smithy/config-resolver": "^4.3.2", "@smithy/core": "^3.16.1", "@smithy/fetch-http-handler": "^5.3.3", "@smithy/hash-node": "^4.2.2", "@smithy/invalid-dependency": "^4.2.2", "@smithy/middleware-content-length": "^4.2.2", "@smithy/middleware-endpoint": "^4.3.3", "@smithy/middleware-retry": "^4.4.3", "@smithy/middleware-serde": "^4.2.2", "@smithy/middleware-stack": "^4.2.2", "@smithy/node-config-provider": "^4.3.2", "@smithy/node-http-handler": "^4.4.1", "@smithy/protocol-http": "^5.3.2", "@smithy/smithy-client": "^4.8.1", "@smithy/types": "^4.7.1", "@smithy/url-parser": "^4.2.2", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.2", "@smithy/util-defaults-mode-node": "^4.2.3", "@smithy/util-endpoints": "^3.2.2", "@smithy/util-middleware": "^4.2.2", "@smithy/util-retry": "^4.2.2", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-lp/sXbdX/S0EYaMYPVKga0omjIUbNNdFi9IJITgKZkLC6CzspihIoHd5GIdl4esMJevtTQQfkVncXTFkf/a4YA=="], + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-YB40IPa7K3iaYX0lSnV9easDOLPLh+fJyUDF3BH8doX4i1AOSsYn86L4lVldmOaSX+DwiaqKHpvk4wPBdcIPWw=="], - "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@smithy/node-config-provider": "^4.3.2", "@smithy/types": "^4.7.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-gzQAkuHI3xyG6toYnH/pju+kc190XmvnB7X84vtN57GjgdQJICt9So/BD0U6h+eSfk9VBnafkVrAzBzWMEFZVw=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eyj2tz1XmDSLSZQ5xnB7cLTVKkSJnYAEoNDSUNhzWPxrBDYeJzIbatecOKceKCU8NBf8gWWZCK/CSY0mDxMO0A=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.911.0", "", { "dependencies": { "@aws-sdk/core": "3.911.0", "@aws-sdk/nested-clients": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/property-provider": "^4.2.2", "@smithy/shared-ini-file-loader": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-O1c5F1pbEImgEe3Vr8j1gpWu69UXWj3nN3vvLGh77hcrG5dZ8I27tSP5RN4Labm8Dnji/6ia+vqSYpN8w6KN5A=="], + "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/types": ["@aws-sdk/types@3.910.0", "", { "dependencies": { "@smithy/types": "^4.7.1", "tslib": "^2.6.2" } }, "sha512-o67gL3vjf4nhfmuSUNNkit0d62QJEwwHLxucwVJkR/rw9mfUtAWsgBs8Tp16cdUbMgsyQtCQilL8RAJDoGtadQ=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-vvw8+VXk0I+IsoxZw0mX9TMJawUJvEsg3EF7zcCSetwhNPAU8Xmlhv7E/sN/FgSmm7b7DsqKoW6rVtQiCs1PWQ=="], - "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@smithy/types": "^4.7.1", "@smithy/url-parser": "^4.2.2", "@smithy/util-endpoints": "^3.2.2", "tslib": "^2.6.2" } }, "sha512-6XgdNe42ibP8zCQgNGDWoOF53RfEKzpU/S7Z29FTTJ7hcZv0SytC0ZNQQZSx4rfBl036YWYwJRoJMlT4AA7q9A=="], + "@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + + "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg=="], - "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.910.0", "", { "dependencies": { "@aws-sdk/types": "3.910.0", "@smithy/types": "^4.7.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-iOdrRdLZHrlINk9pezNZ82P/VxO/UmtmpaOAObUN+xplCUJu31WNM2EE/HccC8PQw6XlAudpdA6HDTGiW6yVGg=="], + "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.911.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.911.0", "@aws-sdk/types": "3.910.0", "@smithy/node-config-provider": "^4.3.2", "@smithy/types": "^4.7.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-3l+f6ooLF6Z6Lz0zGi7vSKSUYn/EePPizv88eZQpEAFunBHv+CSVNPtxhxHfkm7X9tTsV4QGZRIqo3taMLolmA=="], + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.936.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-XOEc7PF9Op00pWV2AYCGDSu5iHgYjIO53Py2VUQTIvP7SRCaCsXmA33mjBvC2Ms6FhSyWNa4aK4naUGIz0hQcw=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.911.0", "", { "dependencies": { "@smithy/types": "^4.7.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-/yh3oe26bZfCVGrIMRM9Z4hvvGJD+qx5tOLlydOkuBkm72aXON7D9+MucjJXTAcI8tF2Yq+JHa0478eHQOhnLg=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.0.1", "", {}, "sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw=="], + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.1", "", {}, "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww=="], "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], @@ -1001,55 +1008,55 @@ "@sinonjs/fake-timers": ["@sinonjs/fake-timers@8.1.0", "", { "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg=="], - "@smithy/abort-controller": ["@smithy/abort-controller@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-xWL9Mf8b7tIFuAlpjKtRPnHrR8XVrwTj5NPYO/QwZPtc0SDLsPxb56V5tzi5yspSMytISHybifez+4jlrx0vkQ=="], + "@smithy/abort-controller": ["@smithy/abort-controller@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA=="], - "@smithy/config-resolver": ["@smithy/config-resolver@4.3.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-xSql8A1Bl41O9JvGU/CtgiLBlwkvpHTSKRlvz9zOBvBCPjXghZ6ZkcVzmV2f7FLAA+80+aqKmIOmy8pEDrtCaw=="], + "@smithy/config-resolver": ["@smithy/config-resolver@4.4.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw=="], - "@smithy/core": ["@smithy/core@3.17.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-stream": "^4.5.3", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Tir3DbfoTO97fEGUZjzGeoXgcQAUBRDTmuH9A8lxuP8ATrgezrAJ6cLuRvwdKN4ZbYNlHgKlBX69Hyu3THYhtg=="], + "@smithy/core": ["@smithy/core@3.18.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.6", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/property-provider": "^4.2.3", "@smithy/types": "^4.8.0", "@smithy/url-parser": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-hA1MQ/WAHly4SYltJKitEsIDVsNmXcQfYBRv2e+q04fnqtAX5qXaybxy/fhUeAMCnQIdAjaGDb04fMHQefWRhw=="], + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/querystring-builder": "^4.2.3", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-bwigPylvivpRLCm+YK9I5wRIYjFESSVwl8JQ1vVx/XhCw0PtCi558NwTnT2DaVCl5pYlImGuQTSwMsZ+pIavRw=="], + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg=="], - "@smithy/hash-node": ["@smithy/hash-node@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6+NOdZDbfuU6s1ISp3UOk5Rg953RJ2aBLNLLBEcamLjHAg1Po9Ha7QIB5ZWhdRUVuOUrT8BVFR+O2KIPmw027g=="], + "@smithy/hash-node": ["@smithy/hash-node@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA=="], - "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-Cc9W5DwDuebXEDMpOpl4iERo8I0KFjTnomK2RMdhhR87GwrSmUmwMxS4P5JdRf+LsjOdIqumcerwRgYMr/tZ9Q=="], + "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A=="], "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="], - "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.3", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-/atXLsT88GwKtfp5Jr0Ks1CSa4+lB+IgRnkNrrYP0h1wL4swHNb0YONEvTceNKNdZGJsye+W2HH8W7olbcPUeA=="], + "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.4", "", { "dependencies": { "@smithy/core": "^3.17.0", "@smithy/middleware-serde": "^4.2.3", "@smithy/node-config-provider": "^4.3.3", "@smithy/shared-ini-file-loader": "^4.3.3", "@smithy/types": "^4.8.0", "@smithy/url-parser": "^4.2.3", "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" } }, "sha512-/RJhpYkMOaUZoJEkddamGPPIYeKICKXOu/ojhn85dKDM0n5iDIhjvYAQLP3K5FPhgB203O3GpWzoK2OehEoIUw=="], + "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.12", "", { "dependencies": { "@smithy/core": "^3.18.5", "@smithy/middleware-serde": "^4.2.6", "@smithy/node-config-provider": "^4.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/protocol-http": "^5.3.3", "@smithy/service-error-classification": "^4.2.3", "@smithy/smithy-client": "^4.9.0", "@smithy/types": "^4.8.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-retry": "^4.2.3", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-vSgABQAkuUHRO03AhR2rWxVQ1un284lkBn+NFawzdahmzksAoOeVMnXXsuPViL4GlhRHXqFaMlc8Mj04OfQk1w=="], + "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/service-error-classification": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-S4kWNKFowYd0lID7/DBqWHOQxmxlsf0jBaos9chQZUWTVOjSW1Ogyh8/ib5tM+agFDJ/TCxuCTvrnlc+9cIBcQ=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.3", "", { "dependencies": { "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-8g4NuUINpYccxiCXM5s1/V+uLtts8NcX4+sPEbvYQDZk4XoJfDpq5y2FQxfmUL89syoldpzNzA0R9nhzdtdKnQ=="], + "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ=="], - "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-iGuOJkH71faPNgOj/gWuEGS6xvQashpLwWB1HjHq1lNNiVfbiJLpZVbhddPuDbx9l4Cgl0vPLq5ltRfSaHfspA=="], + "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ=="], - "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.3", "", { "dependencies": { "@smithy/property-provider": "^4.2.3", "@smithy/shared-ini-file-loader": "^4.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-NzI1eBpBSViOav8NVy1fqOlSfkLgkUjUTlohUSgAEhHaFWA3XJiLditvavIP7OpvTjDp5u2LhtlBhkBlEisMwA=="], + "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.2", "", { "dependencies": { "@smithy/abort-controller": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/querystring-builder": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-MHFvTjts24cjGo1byXqhXrbqm7uznFD/ESFx8npHMWTFQVdBZjrT1hKottmp69LBTRm/JQzP/sn1vPt0/r6AYQ=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw=="], - "@smithy/property-provider": ["@smithy/property-provider@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-+1EZ+Y+njiefCohjlhyOcy1UNYjT+1PwGFHCxA/gYctjg3DQWAU19WigOXAco/Ql8hZokNehpzLd0/+3uCreqQ=="], + "@smithy/property-provider": ["@smithy/property-provider@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg=="], - "@smithy/protocol-http": ["@smithy/protocol-http@5.3.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-Mn7f/1aN2/jecywDcRDvWWWJF4uwg/A0XjFMJtj72DsgHTByfjRltSqcT9NyE9RTdBSN6X1RSXrhn/YWQl8xlw=="], + "@smithy/protocol-http": ["@smithy/protocol-http@5.3.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ=="], - "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-LOVCGCmwMahYUM/P0YnU/AlDQFjcu+gWbFJooC417QRB/lDJlWSn8qmPSDp+s4YVAHOgtgbNG4sR+SxF/VOcJQ=="], + "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg=="], - "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-cYlSNHcTAX/wc1rpblli3aUlLMGgKZ/Oqn8hhjFASXMCXjIqeuQBei0cnq2JR8t4RtU9FpG6uyl6PxyArTiwKA=="], + "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ=="], - "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0" } }, "sha512-NkxsAxFWwsPsQiwFG2MzJ/T7uIR6AQNh1SzcxSUnmmIqIQMlLRQDKhc17M7IYjiuBXhrQRjQTo3CxX+DobS93g=="], + "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0" } }, "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ=="], - "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-9f9Ixej0hFhroOK2TxZfUUDR13WVa8tQzhSzPDgXe5jGL3KmaM9s8XN7RQwqtEypI82q9KHnKS71CJ+q/1xLtQ=="], + "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA=="], - "@smithy/signature-v4": ["@smithy/signature-v4@5.3.3", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.3", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-CmSlUy+eEYbIEYN5N3vvQTRfqt0lJlQkaQUIf+oizu7BbDut0pozfDjBGecfcfWf7c62Yis4JIEgqQ/TCfodaA=="], + "@smithy/signature-v4": ["@smithy/signature-v4@5.3.5", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w=="], - "@smithy/smithy-client": ["@smithy/smithy-client@4.9.0", "", { "dependencies": { "@smithy/core": "^3.17.0", "@smithy/middleware-endpoint": "^4.3.4", "@smithy/middleware-stack": "^4.2.3", "@smithy/protocol-http": "^5.3.3", "@smithy/types": "^4.8.0", "@smithy/util-stream": "^4.5.3", "tslib": "^2.6.2" } }, "sha512-qz7RTd15GGdwJ3ZCeBKLDQuUQ88m+skh2hJwcpPm1VqLeKzgZvXf6SrNbxvx7uOqvvkjCMXqx3YB5PDJyk00ww=="], + "@smithy/smithy-client": ["@smithy/smithy-client@4.9.8", "", { "dependencies": { "@smithy/core": "^3.18.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-stack": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-8xgq3LgKDEFoIrLWBho/oYKyWByw9/corz7vuh1upv7ZBm0ZMjGYBhbn6v643WoIqA9UTcx5A5htEp/YatUwMA=="], - "@smithy/types": ["@smithy/types@4.8.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QpELEHLO8SsQVtqP+MkEgCYTFW0pleGozfs3cZ183ZBj9z3VC1CX1/wtFMK64p+5bhtZo41SeLK1rBRtd25nHQ=="], + "@smithy/types": ["@smithy/types@4.9.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA=="], - "@smithy/url-parser": ["@smithy/url-parser@4.2.3", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-I066AigYvY3d9VlU3zG9XzZg1yT10aNqvCaBTw9EPgu5GrsEl1aUkcMvhkIXascYH1A8W0LQo3B1Kr1cJNcQEw=="], + "@smithy/url-parser": ["@smithy/url-parser@4.2.5", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ=="], "@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="], @@ -1061,25 +1068,25 @@ "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="], - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.3", "", { "dependencies": { "@smithy/property-provider": "^4.2.3", "@smithy/smithy-client": "^4.9.0", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-vqHoybAuZXbFXZqgzquiUXtdY+UT/aU33sxa4GBPkiYklmR20LlCn+d3Wc3yA5ZM13gQ92SZe/D8xh6hkjx+IQ=="], + "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.11", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-yHv+r6wSQXEXTPVCIQTNmXVWs7ekBTpMVErjqZoWkYN75HIFN5y9+/+sYOejfAuvxWGvgzgxbTHa/oz61YTbKw=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.4", "", { "dependencies": { "@smithy/config-resolver": "^4.3.3", "@smithy/credential-provider-imds": "^4.2.3", "@smithy/node-config-provider": "^4.3.3", "@smithy/property-provider": "^4.2.3", "@smithy/smithy-client": "^4.9.0", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-X5/xrPHedifo7hJUUWKlpxVb2oDOiqPUXlvsZv1EZSjILoutLiJyWva3coBpn00e/gPSpH8Rn2eIbgdwHQdW7Q=="], + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.14", "", { "dependencies": { "@smithy/config-resolver": "^4.4.3", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ljZN3iRvaJUgulfvobIuG97q1iUuCMrvXAlkZ4msY+ZuVHQHDIqn7FKZCEj+bx8omz6kF5yQXms/xhzjIO5XiA=="], - "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-aCfxUOVv0CzBIkU10TubdgKSx5uRvzH064kaiPEWfNIvKOtNpu642P4FP1hgOFkjQIkDObrfIDnKMKkeyrejvQ=="], + "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A=="], "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="], - "@smithy/util-middleware": ["@smithy/util-middleware@4.2.3", "", { "dependencies": { "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-v5ObKlSe8PWUHCqEiX2fy1gNv6goiw6E5I/PN2aXg3Fb/hse0xeaAnSpXDiWl7x6LamVKq7senB+m5LOYHUAHw=="], + "@smithy/util-middleware": ["@smithy/util-middleware@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA=="], - "@smithy/util-retry": ["@smithy/util-retry@4.2.3", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-lLPWnakjC0q9z+OtiXk+9RPQiYPNAovt2IXD3CP4LkOnd9NpUsxOjMx1SnoUVB7Orb7fZp67cQMtTBKMFDvOGg=="], + "@smithy/util-retry": ["@smithy/util-retry@4.2.5", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg=="], - "@smithy/util-stream": ["@smithy/util-stream@4.5.3", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.4", "@smithy/node-http-handler": "^4.4.2", "@smithy/types": "^4.8.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-oZvn8a5bwwQBNYHT2eNo0EU8Kkby3jeIg1P2Lu9EQtqDxki1LIjGRJM6dJ5CZUig8QmLxWxqOKWvg3mVoOBs5A=="], + "@smithy/util-stream": ["@smithy/util-stream@4.5.6", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ=="], "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="], "@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="], - "@smithy/util-waiter": ["@smithy/util-waiter@4.2.3", "", { "dependencies": { "@smithy/abort-controller": "^4.2.3", "@smithy/types": "^4.8.0", "tslib": "^2.6.2" } }, "sha512-5+nU///E5sAdD7t3hs4uwvCTWQtTR8JwKwOCSJtBRx0bY1isDo1QwH87vRK86vlFLBTISqoDA2V6xvP6nF1isQ=="], + "@smithy/util-waiter": ["@smithy/util-waiter@4.2.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="], @@ -1223,7 +1230,7 @@ "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], - "@types/nodemailer": ["@types/nodemailer@6.4.20", "", { "dependencies": { "@aws-sdk/client-ses": "^3.731.1", "@types/node": "*" } }, "sha512-uj83z0GqwqMUE6RI4EKptPlav0FYE6vpIlqJAnxzu+/sSezRdbH69rSBCMsdW6DdsCAzoFQZ52c2UIlhRVQYDA=="], + "@types/nodemailer": ["@types/nodemailer@6.4.21", "", { "dependencies": { "@aws-sdk/client-ses": "^3.731.1", "@types/node": "*" } }, "sha512-Eix+sb/Nj28MNnWvO2X1OLrk5vuD4C9SMnb2Vf4itWnxphYeSceqkFX7IdmxTzn+dvmnNz7paMbg4Uc60wSfJg=="], "@types/prettier": ["@types/prettier@2.7.3", "", {}, "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA=="], @@ -1391,6 +1398,8 @@ "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], + "@zone-eu/mailsplit": ["@zone-eu/mailsplit@5.4.7", "", { "dependencies": { "libbase64": "1.3.0", "libmime": "5.3.7", "libqp": "2.1.1" } }, "sha512-jApX86aDgolMz08pP20/J2zcns02NSK3zSiYouf01QQg4250L+GUAWSWicmS7eRvs+Z7wP7QfXrnkaTBGrIpwQ=="], + "abab": ["abab@2.0.6", "", {}, "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="], "abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="], @@ -2621,9 +2630,7 @@ "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], - "mailparser": ["mailparser@3.7.5", "", { "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.7.0", "libmime": "5.3.7", "linkify-it": "5.0.0", "mailsplit": "5.4.6", "nodemailer": "7.0.9", "punycode.js": "2.3.1", "tlds": "1.260.0" } }, "sha512-o59RgZC+4SyCOn4xRH1mtRiZ1PbEmi6si6Ufnd3tbX/V9zmZN1qcqu8xbXY62H6CwIclOT3ppm5u/wV2nujn4g=="], - - "mailsplit": ["mailsplit@5.4.6", "", { "dependencies": { "libbase64": "1.3.0", "libmime": "5.3.7", "libqp": "2.1.1" } }, "sha512-M+cqmzaPG/mEiCDmqQUz8L177JZLZmXAUpq38owtpq2xlXlTSw+kntnxRt2xsxVFFV6+T8Mj/U0l5s7s6e0rNw=="], + "mailparser": ["mailparser@3.9.0", "", { "dependencies": { "@zone-eu/mailsplit": "5.4.7", "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.7.0", "libmime": "5.3.7", "linkify-it": "5.0.0", "nodemailer": "7.0.10", "punycode.js": "2.3.1", "tlds": "1.261.0" } }, "sha512-jpaNLhDjwy0w2f8sySOSRiWREjPqssSc0C2czV98btCXCRX3EyNloQ2IWirmMDj1Ies8Fkm0l96bZBZpDG7qkg=="], "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], @@ -3285,7 +3292,7 @@ "titleize": ["titleize@2.1.0", "", {}, "sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g=="], - "tlds": ["tlds@1.260.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ=="], + "tlds": ["tlds@1.261.0", "", { "bin": { "tlds": "bin.js" } }, "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA=="], "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], @@ -4041,7 +4048,7 @@ "mailparser/html-to-text": ["html-to-text@9.0.5", "", { "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", "dom-serializer": "^2.0.0", "htmlparser2": "^8.0.2", "selderee": "^0.11.0" } }, "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg=="], - "mailparser/nodemailer": ["nodemailer@7.0.9", "", {}, "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ=="], + "mailparser/nodemailer": ["nodemailer@7.0.10", "", {}, "sha512-Us/Se1WtT0ylXgNFfyFSx4LElllVLJXQjWi2Xz17xWw7amDKO2MLtFnVp1WACy7GkVGs+oBlRopVNUzlrGSw1w=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], diff --git a/core/esbuild.config.ts b/core/esbuild.config.ts index 17435cef1..dae89f49c 100644 --- a/core/esbuild.config.ts +++ b/core/esbuild.config.ts @@ -6,9 +6,9 @@ build({ platform: 'node', target: 'node18.20.7', loader: { - '.png': 'dataurl', - '.jpeg': 'dataurl', - '.jpg': 'dataurl', + '.png': 'binary', + '.jpeg': 'binary', + '.jpg': 'binary', }, bundle: true, sourcemap: true, diff --git a/core/package.json b/core/package.json index 06f6e7885..e56a57f43 100644 --- a/core/package.json +++ b/core/package.json @@ -22,6 +22,8 @@ "typecheck": "tsc --noEmit", "lint": "biome check --error-on-warnings .", "lint:fix": "biome check --error-on-warnings . --write", + "locales": "scripts/sort.sh src/emails/locales", + "locales:fix": "scripts/sort.sh src/emails/locales --fix", "clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo" }, "dependencies": { diff --git a/backend/scripts/sort.sh b/core/scripts/sort.sh similarity index 83% rename from backend/scripts/sort.sh rename to core/scripts/sort.sh index d24307d7c..ba54e835a 100755 --- a/backend/scripts/sort.sh +++ b/core/scripts/sort.sh @@ -4,11 +4,11 @@ ROOT_DIR=$(dirname "$0")/.. exit_code=0 -for locale_file in $ROOT_DIR/src/locales/*.json +for locale_file in $ROOT_DIR/"$1"/*.json do jq -M 'to_entries | sort_by(.key) | from_entries' "$locale_file" > tmp.json - if [ "$*" == "--fix" ] + if [ "$2" == "--fix" ] then mv tmp.json "$locale_file" else diff --git a/core/src/emails/locales/en.json b/core/src/emails/locales/en.json index cc8d59c75..b76bc1497 100644 --- a/core/src/emails/locales/en.json +++ b/core/src/emails/locales/en.json @@ -1,104 +1,104 @@ { - "emails": { - "accountActivation": { - "activateAccount": "Activate account", - "emailRegistered": "Your email address has just been registered with Gradido.", - "pleaseClickLink": "Please click here to complete the registration and activate your Gradido account.", - "subject": "Email Verification", - "title": "Email Verification" - }, - "accountMultiRegistration": { - "contactSupport": "Contact support", - "emailExists": "However, an account already exists for your email address.", - "emailReused": "Your email address has just been used again to register an account with Gradido.", - "ifYouAreNotTheOne": "If you did not try to register again, please contact our support:", - "onForgottenPasswordClickLink": "If you have forgotten your password, please click here.", - "subject": "Try To Register Again With Your Email", - "title": "Try To Register Again With Your Email" - }, - "addedContributionMessage": { - "commonGoodContributionMessage": "You have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.", - "readMessage": "Read and reply to message", - "subject": "Message about your common good contribution", - "title": "Message about your common good contribution", - "message": "„{message}“", - "toSeeAndAnswerMessage": "To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." - }, - "contribution": { - "toSeeContributionsAndMessages": "To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." - }, - "contributionChangedByModerator": { - "subject": "Your common good contribution has been changed", - "text": "your common good contribution '{contributionMemo}' has just been changed by {senderFirstName} {senderLastName} and now reads as '{contributionMemoUpdated}'", - "title": "Your common good contribution has been changed" - }, - "contributionConfirmed": { - "commonGoodContributionConfirmed": "Your common good contribution “{contributionMemo}” has just been approved by {senderFirstName} {senderLastName}. Your Gradido account has been credited with {amountGDD} GDD.", - "subject": "Your contribution to the common good was confirmed", - "title": "Your contribution to the common good was confirmed" - }, - "contributionDeleted": { - "commonGoodContributionDeleted": "Your common good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.", - "subject": "Your common good contribution was deleted", - "title": "Your common good contribution was deleted" - }, - "contributionDenied": { - "commonGoodContributionDenied": "Your common good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.", - "subject": "Your common good contribution was rejected", - "title": "Your common good contribution was rejected" - }, - "footer": { - "contactOurSupport": "If you have any further questions, please contact our support.", - "imprint": "Impressum", - "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", - "imprintImageAlt": "Gradido-Akademie Logo", - "privacyPolicy": "Privacy Policy", - "supportEmail": "support@gradido.net" - }, - "general": { - "amountGDD": "Amount: {amountGDD} GDD", - "answerNow": "Reply", - "completeRegistration": "Complete registration", - "contribution": "Contribution: : {contributionMemo}", - "contributionDetails": "Contribution details", - "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account.", - "helloName": "Hello {firstName} {lastName},", - "linkValidity": "The link has a validity of {hours} hours.\nIf the validity of the link has already expired, you can have a new link sent to you here.", - "linkValidityWithMinutes": "The link has a validity of {hours} hours and {minutes} minutes.\nIf the validity of the link has already expired, you can have a new link sent to you here.", - "message": "Message", - "newLink": "New link", - "orCopyLink": "Or copy the link into your browser window.", - "pleaseDoNotReply": "Please do not reply to this email.", - "requestNewLink": "Request new valid link", - "reset": "reset", - "sincerelyYours": "Kind regards,", - "toAccount": "To account", - "transactionDetails": "Transaction details", - "yourGradidoTeam": "your Gradido team" - }, - "resetPassword": { - "pleaseClickLink": "If it was you, please click here.", - "subject": "Reset password", - "title": "Reset password", - "youOrSomeoneResetPassword": "You, or someone else, requested a password reset for this account." - }, - "transactionLinkRedeemed": { - "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) has just redeemed your link.", - "memo": "Message: {transactionMemo}", - "subject": "{senderFirstName} {senderLastName} has redeemed your Gradido link", - "title": "{senderFirstName} {senderLastName} has redeemed your Gradido link" - }, - "transactionReceived": { - "haveReceivedAmountGDDFrom": "You have just received {transactionAmount} GDD from {senderFirstName} {senderLastName}", - "replySubject": "RE: {senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", - "subject": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", - "title": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido" - } - }, - "general": { - "decimalSeparator": "." - }, - "accountMultiRegistration": { - "contactSupport": "accountMultiRegistration.contactSupport" - } -} \ No newline at end of file + "accountMultiRegistration": { + "contactSupport": "accountMultiRegistration.contactSupport" + }, + "emails": { + "accountActivation": { + "activateAccount": "Activate account", + "emailRegistered": "Your email address has just been registered with Gradido.", + "pleaseClickLink": "Please click here to complete the registration and activate your Gradido account.", + "subject": "Email Verification", + "title": "Email Verification" + }, + "accountMultiRegistration": { + "contactSupport": "Contact support", + "emailExists": "However, an account already exists for your email address.", + "emailReused": "Your email address has just been used again to register an account with Gradido.", + "ifYouAreNotTheOne": "If you did not try to register again, please contact our support:", + "onForgottenPasswordClickLink": "If you have forgotten your password, please click here.", + "subject": "Try To Register Again With Your Email", + "title": "Try To Register Again With Your Email" + }, + "addedContributionMessage": { + "commonGoodContributionMessage": "You have received a message from {senderFirstName} {senderLastName} regarding your common good contribution “{contributionMemo}”.", + "readMessage": "Read and reply to message", + "subject": "Message about your common good contribution", + "title": "Message about your common good contribution", + "message": "„{message}“", + "toSeeAndAnswerMessage": "To reply to the message, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." + }, + "contribution": { + "toSeeContributionsAndMessages": "To see your common good contributions and related messages, go to the “Creation” menu in your Gradido account and click on the “My contributions” tab." + }, + "contributionChangedByModerator": { + "subject": "Your common good contribution has been changed", + "text": "your common good contribution '{contributionMemo}' has just been changed by {senderFirstName} {senderLastName} and now reads as '{contributionMemoUpdated}'", + "title": "Your common good contribution has been changed" + }, + "contributionConfirmed": { + "commonGoodContributionConfirmed": "Your common good contribution “{contributionMemo}” has just been approved by {senderFirstName} {senderLastName}. Your Gradido account has been credited with {amountGDD} GDD.", + "subject": "Your contribution to the common good was confirmed", + "title": "Your contribution to the common good was confirmed" + }, + "contributionDeleted": { + "commonGoodContributionDeleted": "Your common good contribution “{contributionMemo}” was deleted by {senderFirstName} {senderLastName}.", + "subject": "Your common good contribution was deleted", + "title": "Your common good contribution was deleted" + }, + "contributionDenied": { + "commonGoodContributionDenied": "Your common good contribution “{contributionMemo}” was rejected by {senderFirstName} {senderLastName}.", + "subject": "Your common good contribution was rejected", + "title": "Your common good contribution was rejected" + }, + "footer": { + "contactOurSupport": "If you have any further questions, please contact our support.", + "imprint": "Impressum", + "imprintAddress": "Gradido-Akademie\nInstitut für Wirtschaftsbionik\nPfarrweg 2\n74653 Künzelsau\nDeutschland", + "imprintImageAlt": "Gradido-Akademie Logo", + "privacyPolicy": "Privacy Policy", + "supportEmail": "support@gradido.net" + }, + "general": { + "amountGDD": "Amount: {amountGDD} GDD", + "answerNow": "Reply", + "completeRegistration": "Complete registration", + "contribution": "Contribution: : {contributionMemo}", + "contributionDetails": "Contribution details", + "detailsYouFindOnLinkToYourAccount": "You can find transaction details in your Gradido account.", + "helloName": "Hello {firstName} {lastName},", + "linkValidity": "The link has a validity of {hours} hours.\nIf the validity of the link has already expired, you can have a new link sent to you here.", + "linkValidityWithMinutes": "The link has a validity of {hours} hours and {minutes} minutes.\nIf the validity of the link has already expired, you can have a new link sent to you here.", + "message": "Message", + "newLink": "New link", + "orCopyLink": "Or copy the link into your browser window.", + "pleaseDoNotReply": "Please do not reply to this email.", + "requestNewLink": "Request new valid link", + "reset": "reset", + "sincerelyYours": "Kind regards,", + "toAccount": "To account", + "transactionDetails": "Transaction details", + "yourGradidoTeam": "your Gradido team" + }, + "resetPassword": { + "pleaseClickLink": "If it was you, please click here.", + "subject": "Reset password", + "title": "Reset password", + "youOrSomeoneResetPassword": "You, or someone else, requested a password reset for this account." + }, + "transactionLinkRedeemed": { + "hasRedeemedYourLink": "{senderFirstName} {senderLastName} ({senderEmail}) has just redeemed your link.", + "memo": "Message: {transactionMemo}", + "subject": "{senderFirstName} {senderLastName} has redeemed your Gradido link", + "title": "{senderFirstName} {senderLastName} has redeemed your Gradido link" + }, + "transactionReceived": { + "haveReceivedAmountGDDFrom": "You have just received {transactionAmount} GDD from {senderFirstName} {senderLastName}", + "replySubject": "RE: {senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", + "subject": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido", + "title": "{senderFirstName} {senderLastName} has sent you {transactionAmount} Gradido" + } + }, + "general": { + "decimalSeparator": "." + } +} diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts index 02d6de130..b05b93ca7 100644 --- a/core/src/emails/sendEmailTranslated.ts +++ b/core/src/emails/sendEmailTranslated.ts @@ -1,5 +1,4 @@ import path from 'path' - import Email from 'email-templates' import { i18n } from './localization' import { createTransport } from 'nodemailer' @@ -60,8 +59,8 @@ export const sendEmailTranslated = async ({ pass: CONFIG.EMAIL_PASSWORD, }, }) - i18n.setLocale(locals.language as string) // for email + i18n.setLocale(locals.language as string) // for email // TESTING: see 'README.md' const email = new Email({ message: { @@ -71,7 +70,6 @@ export const sendEmailTranslated = async ({ transport, preview: false, }) - const resultSend = await email .send({ template: path.join(__dirname, 'templates', template), @@ -79,8 +77,9 @@ export const sendEmailTranslated = async ({ ...receiver, attachments: [ { - // filename: 'gradido-header.jpeg', - content: gradidoHeader, + filename: 'gradido-header.jpeg', + // content: gradidoHeader, + path: path.join(__dirname, 'templates/includes/gradido-header.jpeg'), cid: 'gradidoheader', }, { @@ -115,7 +114,7 @@ export const sendEmailTranslated = async ({ }) .catch((error: unknown) => { logger.error('Error sending notification email', error) - return error + throw error }) return resultSend diff --git a/core/turbo.json b/core/turbo.json new file mode 100644 index 000000000..067806d37 --- /dev/null +++ b/core/turbo.json @@ -0,0 +1,13 @@ +{ + "extends": ["//"], + "tasks": { + "locales": {}, + "locales:fix": {}, + "lint": { + "dependsOn": ["locales"] + }, + "lint:fix": { + "dependsOn": ["locales:fix"] + } + } +} \ No newline at end of file From 0cb4f5fb695c8db6d522a51b884bd195db2bbf40 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 16:48:28 +0100 Subject: [PATCH 144/226] fix --- core/src/emails/sendEmailTranslated.ts | 5 ++--- core/src/emails/sendEmailVariants.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts index b05b93ca7..30ae03112 100644 --- a/core/src/emails/sendEmailTranslated.ts +++ b/core/src/emails/sendEmailTranslated.ts @@ -77,9 +77,8 @@ export const sendEmailTranslated = async ({ ...receiver, attachments: [ { - filename: 'gradido-header.jpeg', - // content: gradidoHeader, - path: path.join(__dirname, 'templates/includes/gradido-header.jpeg'), + // filename: 'gradido-header.jpeg', + content: gradidoHeader, cid: 'gradidoheader', }, { diff --git a/core/src/emails/sendEmailVariants.ts b/core/src/emails/sendEmailVariants.ts index 75f5c468d..da67beefb 100644 --- a/core/src/emails/sendEmailVariants.ts +++ b/core/src/emails/sendEmailVariants.ts @@ -1,7 +1,7 @@ import { Decimal } from 'decimal.js-light' import { CONFIG } from '../config' -import { decimalSeparatorByLanguage } from 'core' +import { decimalSeparatorByLanguage } from '../util/utilities' import { sendEmailTranslated } from './sendEmailTranslated' From 68e09d432fc596abc4ceb893c44e83481d7a6c3a Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 17:03:44 +0100 Subject: [PATCH 145/226] fix ci errors --- .github/workflows/test_backend.yml | 17 +---------------- .github/workflows/test_core.yml | 15 +++++++++++++++ backend/Dockerfile | 3 +-- backend/package.json | 2 +- federation/Dockerfile | 2 ++ federation/package.json | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index c0e65078f..f85fdfa4c 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -92,19 +92,4 @@ jobs: bun install --global --no-save turbo@^2 - name: Backend | Typecheck - run: turbo backend#typecheck backend#build - - locales: - if: needs.files-changed.outputs.backend == 'true' - name: Locales - Backend - needs: files-changed - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: install bun - uses: oven-sh/setup-bun@v2 - - - name: Backend | Locales - run: cd backend && bun locales \ No newline at end of file + run: turbo backend#typecheck backend#build \ No newline at end of file diff --git a/.github/workflows/test_core.yml b/.github/workflows/test_core.yml index ff5f29c1a..f3857e2ae 100644 --- a/.github/workflows/test_core.yml +++ b/.github/workflows/test_core.yml @@ -43,3 +43,18 @@ jobs: - name: typecheck && unit test run: turbo core#test core#typecheck + locales: + if: needs.files-changed.outputs.core == 'true' + name: Locales - Core + needs: files-changed + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: install bun + uses: oven-sh/setup-bun@v2 + + - name: Core | Locales + run: cd core && bun locales + diff --git a/backend/Dockerfile b/backend/Dockerfile index eeab1ac17..d3d549cab 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -114,8 +114,7 @@ COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/backend/build/worker.js ./wo # add node_modules from production_node_modules COPY --chown=app:app --from=production-node-modules ${DOCKER_WORKDIR}/node_modules ./node_modules -# Copy locales -COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/backend/locales ./locales +COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/core/build/templates ./templates # Run command CMD ["node", "index.js"] diff --git a/backend/package.json b/backend/package.json index 0a1bab487..463683372 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,7 @@ "author": "Gradido Academy - https://www.gradido.net", "main": "src/index.ts", "scripts": { - "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/src/emails/templates build/templates", + "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/build/templates build/templates", "dev": "cross-env TZ=UTC nodemon -w src --ext ts,pug,json,css -r tsconfig-paths/register src/index.ts", "test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --runInBand --forceExit --detectOpenHandles", "test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_backend jest --coverage --runInBand --forceExit --detectOpenHandles", diff --git a/federation/Dockerfile b/federation/Dockerfile index c3a45bf3d..c754eced6 100644 --- a/federation/Dockerfile +++ b/federation/Dockerfile @@ -116,5 +116,7 @@ COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/federation/build/index.js ./ # add node_modules from production_node_modules COPY --chown=app:app --from=production-node-modules ${DOCKER_WORKDIR}/node_modules ./node_modules +COPY --chown=app:app --from=build ${DOCKER_WORKDIR}/core/build/templates ./templates + # Run command CMD ["node", "index.js"] \ No newline at end of file diff --git a/federation/package.json b/federation/package.json index 057b22a98..fcf1365ab 100644 --- a/federation/package.json +++ b/federation/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "private": false, "scripts": { - "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/src/emails/templates build/templates", + "build": "ts-node ./esbuild.config.ts && mkdirp build/templates/ && ncp ../core/build/templates build/templates", "start": "cross-env TZ=UTC NODE_ENV=production node build/index.js", "start:bun": "cross-env TZ=UTC NODE_ENV=production bun build/index.js", "dev": "cross-env TZ=UTC nodemon -w src --ext ts,json,css -r tsconfig-paths/register src/index.ts", From e6a191838cc4e565bab4a21b7138d94c85117b63 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 17:07:18 +0100 Subject: [PATCH 146/226] core: copy email templates into build --- core/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/package.json b/core/package.json index e56a57f43..93c7431ad 100644 --- a/core/package.json +++ b/core/package.json @@ -15,7 +15,7 @@ "license": "Apache-2.0", "private": true, "scripts": { - "build": "bun esbuild.config.ts", + "build": "bun esbuild.config.ts && mkdirp build/templates/ && ncp src/emails/templates build/templates", "build:bun": "bun build src/index.ts --outdir=build --target=bun --packages=external", "test": "bun test", "test:debug": "bun test --inspect-brk", @@ -53,6 +53,8 @@ "dotenv": "^10.0.0", "graphql-request": "5.0.0", "jest": "27.2.4", + "mkdirp": "^3.0.1", + "ncp": "^2.0.0", "type-graphql": "^1.1.1", "typescript": "^4.9.5" }, From c5bca631451e4d06c0aa25d40c7f7c23b0c82161 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 17:15:11 +0100 Subject: [PATCH 147/226] increase bun version --- .bun-version | 2 +- bun.lock | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.bun-version b/.bun-version index 589268e6f..785cda807 100644 --- a/.bun-version +++ b/.bun-version @@ -1 +1 @@ -1.3.0 \ No newline at end of file +1.3.3 \ No newline at end of file diff --git a/bun.lock b/bun.lock index 9b449354c..6dd175b61 100644 --- a/bun.lock +++ b/bun.lock @@ -210,6 +210,8 @@ "dotenv": "^10.0.0", "graphql-request": "5.0.0", "jest": "27.2.4", + "mkdirp": "^3.0.1", + "ncp": "^2.0.0", "type-graphql": "^1.1.1", "typescript": "^4.9.5", }, From 7e793f13f79278a35c22beaa0be1dc4df55f5771 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 24 Nov 2025 18:03:42 +0100 Subject: [PATCH 148/226] fix backend unit test errors --- .bun-version | 2 +- .../resolver/ContributionMessageResolver.test.ts | 4 +--- .../graphql/resolver/ContributionResolver.test.ts | 13 ++++--------- backend/src/graphql/resolver/UserResolver.test.ts | 10 +++++----- backend/test/testSetup.ts | 2 +- backend/tsconfig.json | 2 +- 6 files changed, 13 insertions(+), 20 deletions(-) diff --git a/.bun-version b/.bun-version index 785cda807..589268e6f 100644 --- a/.bun-version +++ b/.bun-version @@ -1 +1 @@ -1.3.3 \ No newline at end of file +1.3.0 \ No newline at end of file diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index d29bf5235..483747b90 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -34,9 +34,7 @@ jest.mock('core', () => { return { __esModule: true, ...originalModule, - sendAddedContributionMessageEmail: jest.fn((a) => - originalModule.sendAddedContributionMessageEmail(a), - ), + sendAddedContributionMessageEmail: jest.fn(), } }) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index fd31a5275..31d405942 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -58,15 +58,10 @@ jest.mock('core', () => { return { __esModule: true, ...originalModule, - sendContributionDeniedEmail: jest.fn((a) => - originalModule.sendContributionDeniedEmail(a), - ), - sendContributionConfirmedEmail: jest.fn((a) => - originalModule.sendContributionConfirmedEmail(a), - ), - sendContributionDeletedEmail: jest.fn((a) => - originalModule.sendContributionDeletedEmail(a), - ), + sendContributionDeniedEmail: jest.fn(), + sendContributionConfirmedEmail: jest.fn(), + sendContributionDeletedEmail: jest.fn(), + sendEmailTranslated: jest.fn(), } }) jest.mock('@/password/EncryptorUtils') diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index d5bad3bc8..0fd06c0d1 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -78,11 +78,10 @@ jest.mock('core', () => { return { __esModule: true, ...originalModule, - sendAccountActivationEmail: jest.fn((a) => originalModule.sendAccountActivationEmail(a)), - sendAccountMultiRegistrationEmail: jest.fn((a) => - originalModule.sendAccountMultiRegistrationEmail(a), - ), - sendResetPasswordEmail: jest.fn((a) => originalModule.sendResetPasswordEmail(a)), + sendAccountActivationEmail: jest.fn(), + sendAccountMultiRegistrationEmail: jest.fn(), + sendResetPasswordEmail: jest.fn(), + sendEmailTranslated: jest.fn(), } }) @@ -154,6 +153,7 @@ describe('UserResolver', () => { expect(result).toEqual( expect.objectContaining({ data: { createUser: { id: expect.any(Number) } } }), ) + }) describe('valid input data', () => { diff --git a/backend/test/testSetup.ts b/backend/test/testSetup.ts index 6a009e652..841046e0f 100644 --- a/backend/test/testSetup.ts +++ b/backend/test/testSetup.ts @@ -3,7 +3,7 @@ import { CONFIG } from '@/config' import { CONFIG as CORE_CONFIG } from 'core' import { getLogger, printLogs, clearLogs } from 'config-schema/test/testSetup' -CORE_CONFIG.EMAIL = true +CORE_CONFIG.EMAIL = false CORE_CONFIG.EMAIL_TEST_MODUS = false CONFIG.HUMHUB_ACTIVE = false CONFIG.GMS_ACTIVE = false diff --git a/backend/tsconfig.json b/backend/tsconfig.json index d330e2b81..b71bf1938 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -87,7 +87,7 @@ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ }, "include": [ - "../core/src/types", + "../core/src/types" ], "ts-node": { "swc": true From 1d8582ab407f20573445f3a0013b352c80a824a0 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Tue, 25 Nov 2025 03:00:27 +0100 Subject: [PATCH 149/226] invoke redis.quit in test.afterAll --- backend/src/emails/sendEmailVariants.test.ts | 6 +++++- backend/src/federation/validateCommunities.test.ts | 6 +++++- backend/src/graphql/resolver/CommunityResolver.test.ts | 6 +++++- .../graphql/resolver/ContributionLinkResolver.test.ts | 5 +++++ .../resolver/ContributionMessageResolver.test.ts | 5 +++++ .../src/graphql/resolver/ContributionResolver.test.ts | 5 +++++ backend/src/graphql/resolver/EmailOptinCodes.test.ts | 5 +++++ backend/src/graphql/resolver/KlicktippResolver.test.ts | 4 ++++ .../graphql/resolver/TransactionLinkResolver.test.ts | 5 +++++ .../src/graphql/resolver/TransactionResolver.test.ts | 3 +++ backend/src/graphql/resolver/UserResolver.test.ts | 5 +++++ backend/src/graphql/resolver/semaphore.test.ts | 10 ++++++++++ backend/src/graphql/resolver/util/creations.test.ts | 5 +++++ backend/src/util/klicktipp.test.ts | 5 +++++ database/src/AppDatabase.ts | 3 ++- 15 files changed, 74 insertions(+), 4 deletions(-) diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts index 74eb940ed..858efdadd 100644 --- a/backend/src/emails/sendEmailVariants.test.ts +++ b/backend/src/emails/sendEmailVariants.test.ts @@ -5,7 +5,7 @@ import { DataSource } from 'typeorm' import { testEnvironment } from '@test/helpers' import { i18n as localization } from '@test/testSetup' import { getLogger } from 'config-schema/test/testSetup' - +import { AppDatabase } from 'database' import { CONFIG } from '@/config' import * as sendEmailTranslatedApi from './sendEmailTranslated' @@ -47,19 +47,23 @@ jest.mock('nodemailer', () => { }) let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { testEnv = await testEnvironment(getLogger('apollo'), localization) con = testEnv.con + db = testEnv.db }) afterAll(async () => { await con.destroy() + await db.getRedisClient().quit() }) const sendEmailTranslatedSpy = jest.spyOn(sendEmailTranslatedApi, 'sendEmailTranslated') diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 949195652..0506f33be 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -7,7 +7,7 @@ import { DataSource, Not } from 'typeorm' import { cleanDB, testEnvironment } from '@test/helpers' import { getLogger } from 'config-schema/test/testSetup' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' - +import { AppDatabase } from 'database' import { validateCommunities } from './validateCommunities' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.validateCommunities`) @@ -16,21 +16,25 @@ const federationClientLogger = getLogger( ) let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { testEnv = await testEnvironment(logger) con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { // await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('validate Communities', () => { diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 57173c9d1..126313388 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -20,6 +20,7 @@ import { createCommunity, createVerifiedFederatedCommunity } from 'database/src/ import { getLogger } from 'config-schema/test/testSetup' import { CONFIG } from '@/config' +import { AppDatabase } from 'database' jest.mock('@/password/EncryptorUtils') @@ -29,11 +30,12 @@ CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER = 1000 let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource - +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } const peterLoginData = { @@ -47,6 +49,7 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db await cleanDB() // reset id auto increment await DbCommunity.clear() @@ -55,6 +58,7 @@ beforeAll(async () => { afterAll(async () => { await con.destroy() + await db.getRedisClient().quit() }) // real valid ed25519 key pairs diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index fa855f4b0..c67b900f8 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -19,6 +19,7 @@ import { listContributionLinks } from '@/seeds/graphql/queries' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { getLogger } from 'config-schema/test/testSetup' +import { AppDatabase } from 'database' jest.mock('@/password/EncryptorUtils') @@ -27,10 +28,12 @@ const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { @@ -38,6 +41,7 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db await cleanDB() await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) @@ -46,6 +50,7 @@ beforeAll(async () => { afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('Contribution Links', () => { diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 962b77766..b5a4638b9 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -22,6 +22,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { getLogger} from 'config-schema/test/testSetup' +import { AppDatabase } from 'database' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.ContributionMessageResolver`) const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) @@ -43,10 +44,12 @@ jest.mock('@/emails/sendEmailVariants', () => { let mutate: ApolloServerTestClient['mutate'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } let result: any @@ -54,12 +57,14 @@ beforeAll(async () => { testEnv = await testEnvironment(logger, localization) mutate = testEnv.mutate con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('ContributionMessageResolver', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 6dee20592..0f324bf07 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -53,6 +53,7 @@ import { stephenHawking } from '@/seeds/users/stephen-hawking' import { getFirstDayOfPreviousNMonth } from 'core' import { getLogger } from 'config-schema/test/testSetup' import { getLogger as originalGetLogger } from 'log4js' +import { AppDatabase } from 'database' jest.mock('@/emails/sendEmailVariants') jest.mock('@/password/EncryptorUtils') @@ -62,10 +63,12 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } let creation: Contribution | null let admin: User @@ -81,12 +84,14 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('ContributionResolver', () => { diff --git a/backend/src/graphql/resolver/EmailOptinCodes.test.ts b/backend/src/graphql/resolver/EmailOptinCodes.test.ts index b916d23b6..4c13cf3f3 100644 --- a/backend/src/graphql/resolver/EmailOptinCodes.test.ts +++ b/backend/src/graphql/resolver/EmailOptinCodes.test.ts @@ -9,14 +9,17 @@ import { CONFIG } from '@/config' import { writeHomeCommunityEntry } from '@/seeds/community' import { createUser, forgotPassword, setPassword } from '@/seeds/graphql/mutations' import { queryOptIn } from '@/seeds/graphql/queries' +import { AppDatabase } from 'database' let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } CONFIG.EMAIL_CODE_VALID_TIME = 1440 @@ -28,12 +31,14 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('EmailOptinCodes', () => { diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index f3ac85ef4..db9d4f680 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -10,6 +10,7 @@ import { userFactory } from '@/seeds/factory/user' import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' +import { AppDatabase } from 'database' jest.mock('@/password/EncryptorUtils') @@ -18,17 +19,20 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.Klicktip let testEnv: any let mutate: any let con: any +let db: AppDatabase beforeAll(async () => { testEnv = await testEnvironment(logger, localization) mutate = testEnv.mutate con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('KlicktippResolver', () => { diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 475d47150..d893f723f 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -36,6 +36,7 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLogger } from 'config-schema/test/testSetup' import { transactionLinkCode } from './TransactionLinkResolver' import { CONFIG } from '@/config' +import { AppDatabase } from 'database' const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) @@ -50,10 +51,12 @@ CONFIG.DLT_CONNECTOR = false let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } let user: User @@ -63,6 +66,7 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db await cleanDB() await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) @@ -71,6 +75,7 @@ beforeAll(async () => { afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('TransactionLinkResolver', () => { diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index a134ca84b..450317f87 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -34,6 +34,7 @@ import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' import { getLogger } from 'config-schema/test/testSetup' import { CONFIG } from '@/config' +import { AppDatabase } from 'database' jest.mock('@/password/EncryptorUtils') @@ -48,6 +49,7 @@ let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { @@ -61,6 +63,7 @@ beforeAll(async () => { afterAll(async () => { await cleanDB() await con.destroy() // close() + await testEnv.db.getRedisClient().quit() }) let bobData: any diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index cee570c94..31f3f69d7 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,6 +1,7 @@ import { UserInputError } from 'apollo-server-express' import { ApolloServerTestClient } from 'apollo-server-testing' import { + AppDatabase, Community as DbCommunity, Event as DbEvent, TransactionLink, @@ -105,10 +106,12 @@ let user: User let mutate: ApolloServerTestClient['mutate'] let query: ApolloServerTestClient['query'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { @@ -116,6 +119,7 @@ beforeAll(async () => { mutate = testEnv.mutate query = testEnv.query con = testEnv.con + db = testEnv.db CONFIG.HUMHUB_ACTIVE = false CONFIG.DLT_CONNECTOR = false await cleanDB() @@ -124,6 +128,7 @@ beforeAll(async () => { afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('UserResolver', () => { diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 54adfcee3..307eb5d82 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -70,6 +70,7 @@ async function fakeWork(runOrder: RunOrder, index: number) { describe('semaphore', () => { it("didn't should run in parallel", async () => { const runOrder: RunOrder = {} + /* await Promise.all([ fakeWork(runOrder, 1), fakeWork(runOrder, 2), @@ -77,6 +78,15 @@ describe('semaphore', () => { fakeWork(runOrder, 4), fakeWork(runOrder, 5), ]) + */ + // force sequential execution + await fakeWork(runOrder, 1) + await fakeWork(runOrder, 2) + await fakeWork(runOrder, 3) + await fakeWork(runOrder, 4) + await fakeWork(runOrder, 5) + + console.log('runOrder=', runOrder) expect(runOrder[1].start).toBeLessThan(runOrder[1].end) expect(runOrder[1].start).toBeLessThan(runOrder[2].start) expect(runOrder[2].start).toBeLessThan(runOrder[2].end) diff --git a/backend/src/graphql/resolver/util/creations.test.ts b/backend/src/graphql/resolver/util/creations.test.ts index 26c09fb79..e490ab20a 100644 --- a/backend/src/graphql/resolver/util/creations.test.ts +++ b/backend/src/graphql/resolver/util/creations.test.ts @@ -1,6 +1,7 @@ import { ApolloServerTestClient } from 'apollo-server-testing' import { Contribution, User } from 'database' import { DataSource } from 'typeorm' +import { AppDatabase } from 'database' import { cleanDB, contributionDateFormatter, testEnvironment } from '@test/helpers' @@ -18,22 +19,26 @@ CONFIG.HUMHUB_ACTIVE = false let mutate: ApolloServerTestClient['mutate'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { testEnv = await testEnvironment() mutate = testEnv.mutate con = testEnv.con + db = testEnv.db await cleanDB() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) const setZeroHours = (date: Date): Date => { diff --git a/backend/src/util/klicktipp.test.ts b/backend/src/util/klicktipp.test.ts index 497753c9f..50fe4a1f7 100644 --- a/backend/src/util/klicktipp.test.ts +++ b/backend/src/util/klicktipp.test.ts @@ -1,6 +1,7 @@ import { ApolloServerTestClient } from 'apollo-server-testing' import { Event as DbEvent } from 'database' import { DataSource } from 'typeorm' +import { AppDatabase } from 'database' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' @@ -19,22 +20,26 @@ jest.mock('@/password/EncryptorUtils') let mutate: ApolloServerTestClient['mutate'] let con: DataSource +let db: AppDatabase let testEnv: { mutate: ApolloServerTestClient['mutate'] query: ApolloServerTestClient['query'] con: DataSource + db: AppDatabase } beforeAll(async () => { testEnv = await testEnvironment() mutate = testEnv.mutate con = testEnv.con + db = testEnv.db await DbEvent.clear() }) afterAll(async () => { await cleanDB() await con.destroy() + await db.getRedisClient().quit() }) describe('klicktipp', () => { diff --git a/database/src/AppDatabase.ts b/database/src/AppDatabase.ts index 13e33a8d3..9cd798a26 100644 --- a/database/src/AppDatabase.ts +++ b/database/src/AppDatabase.ts @@ -12,7 +12,7 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.AppDatabase`) export class AppDatabase { private static instance: AppDatabase private dataSource: DBDataSource | undefined - private redisClient: Redis + private redisClient: Redis | undefined /** * The Singleton's constructor should always be private to prevent direct @@ -100,6 +100,7 @@ export class AppDatabase { await this.dataSource?.destroy() if (this.redisClient) { this.redisClient.quit() + this.redisClient = undefined } } From 331d750dfc090d84eae9b0ecba629de3aac8bd3b Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 01:36:07 +0100 Subject: [PATCH 150/226] add "redis-semaphore": "^5.6.2" --- backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/package.json b/backend/package.json index 5921bca92..5bc9c7837 100644 --- a/backend/package.json +++ b/backend/package.json @@ -33,6 +33,7 @@ "dependencies": { "cross-env": "^7.0.3", "email-templates": "^10.0.1", + "redis-semaphore": "^5.6.2", "sodium-native": "^3.4.1" }, "devDependencies": { From 93a7403f25d4934b7d0fb5a8b7dd22b348e12990 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 01:39:51 +0100 Subject: [PATCH 151/226] add redis-semaphore": "^5.6.2" --- federation/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/federation/package.json b/federation/package.json index 7908ddf29..a7cf567ee 100644 --- a/federation/package.json +++ b/federation/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "cross-env": "^7.0.3", + "redis-semaphore": "^5.6.2", "sodium-native": "^3.4.1" }, "devDependencies": { From d47fd51433b3cec2a822ac74abccdd94033628e7 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 01:51:33 +0100 Subject: [PATCH 152/226] add redis-semaphore": "^5.6.2" --- bun.lock | 3 +++ core/package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/bun.lock b/bun.lock index b4e5a9a8d..60f575d84 100644 --- a/bun.lock +++ b/bun.lock @@ -94,6 +94,7 @@ "dependencies": { "cross-env": "^7.0.3", "email-templates": "^10.0.1", + "redis-semaphore": "^5.6.2", "sodium-native": "^3.4.1", }, "devDependencies": { @@ -194,6 +195,7 @@ "joi": "^17.13.3", "jose": "^4.14.4", "log4js": "^6.9.1", + "redis-semaphore": "^5.6.2", "shared": "*", "sodium-native": "^3.4.1", "zod": "^3.25.61", @@ -297,6 +299,7 @@ "version": "2.7.0", "dependencies": { "cross-env": "^7.0.3", + "redis-semaphore": "^5.6.2", "sodium-native": "^3.4.1", }, "devDependencies": { diff --git a/core/package.json b/core/package.json index 3771e3a8e..e4d9a109e 100644 --- a/core/package.json +++ b/core/package.json @@ -31,6 +31,7 @@ "joi": "^17.13.3", "jose": "^4.14.4", "log4js": "^6.9.1", + "redis-semaphore": "^5.6.2", "shared": "*", "sodium-native": "^3.4.1", "zod": "^3.25.61" From be0c9d0e34803bf4217d857581089bd2661ffd13 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 09:17:43 +0100 Subject: [PATCH 153/226] add link in frontend to inspector, change Env var name --- backend/src/config/index.ts | 3 +-- backend/src/config/schema.ts | 15 ++++----------- config-schema/src/commonSchema.ts | 5 +++++ deployment/bare_metal/.env.dist | 2 +- deployment/bare_metal/start.sh | 8 ++++---- frontend/src/components/ContentFooter.vue | 7 +++++++ frontend/src/config/schema.js | 2 ++ frontend/src/locales/de.json | 1 + frontend/src/locales/en.json | 1 + frontend/src/locales/es.json | 1 + frontend/src/locales/fr.json | 1 + frontend/src/locales/nl.json | 1 + frontend/vite.config.mjs | 1 + 13 files changed, 30 insertions(+), 18 deletions(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index f29f0b0f7..be33b20c9 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -17,6 +17,7 @@ const logging = { const server = { BACKEND_PORT: process.env.BACKEND_PORT ?? 4000, + DLT_ACTIVE: process.env.DLT_ACTIVE === 'true' || false, JWT_SECRET: process.env.JWT_SECRET ?? 'secret123', JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN ?? '10m', REDEEM_JWT_TOKEN_EXPIRATION: process.env.REDEEM_JWT_TOKEN_EXPIRATION ?? '10m', @@ -41,9 +42,7 @@ const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNIT const DLT_CONNECTOR_PORT = process.env.DLT_CONNECTOR_PORT ?? 6010 const dltConnector = { - DLT_CONNECTOR: process.env.DLT_CONNECTOR === 'true' || false, DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `${COMMUNITY_URL}:${DLT_CONNECTOR_PORT}`, - DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: process.env.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER ?? '~/.gradido', } const community = { diff --git a/backend/src/config/schema.ts b/backend/src/config/schema.ts index 4b13b4e64..28b1f1803 100644 --- a/backend/src/config/schema.ts +++ b/backend/src/config/schema.ts @@ -4,6 +4,7 @@ import { COMMUNITY_SUPPORT_MAIL, COMMUNITY_URL, DECAY_START_TIME, + DLT_ACTIVE, GDT_ACTIVE, GDT_API_URL, GMS_ACTIVE, @@ -27,6 +28,7 @@ export const schema = Joi.object({ COMMUNITY_DESCRIPTION, COMMUNITY_SUPPORT_MAIL, DECAY_START_TIME, + DLT_ACTIVE, GDT_API_URL, GDT_ACTIVE, GMS_ACTIVE, @@ -68,20 +70,11 @@ export const schema = Joi.object({ .default('http://0.0.0.0/redeem/CL-') .required(), - DLT_CONNECTOR: Joi.boolean() - .description('Flag to indicate if DLT-Connector is used. (Still in development)') - .default(false) - .required(), - DLT_CONNECTOR_URL: Joi.string() .uri({ scheme: ['http', 'https'] }) .default('http://localhost:6010') - .when('DLT_CONNECTOR', { is: true, then: Joi.required() }) - .description('The URL for GDT API endpoint'), - - DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: Joi.string() - .default('~/.gradido') - .description('The home folder for the gradido dlt node server'), + .when('DLT_ACTIVE', { is: true, then: Joi.required() }) + .description('The URL for DLT connector'), EMAIL: Joi.boolean() .default(false) diff --git a/config-schema/src/commonSchema.ts b/config-schema/src/commonSchema.ts index 250ea3182..f28115ea7 100644 --- a/config-schema/src/commonSchema.ts +++ b/config-schema/src/commonSchema.ts @@ -35,6 +35,11 @@ export const COMMUNITY_URL = Joi.string() .default('http://0.0.0.0') .required() +export const DLT_ACTIVE = Joi.boolean() + .description('Flag to indicate if the DLT (Decentralized Ledger Technology) service is used.') + .default(false) + .required() + export const GRAPHQL_URI = Joi.string() .uri({ scheme: ['http', 'https'] }) .description( diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index a0e449ac2..7be3ead1e 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -90,7 +90,7 @@ GDT_ACTIVE=false AUTO_POLL_INTERVAL=30000 # DLT-Connector (still in develop) -DLT_CONNECTOR=false +DLT_ACTIVE=false DLT_CONNECTOR_PORT=6010 DLT_NODE_SERVER_PORT=8340 DLT_NODE_SERVER_URL=$URL_PROTOCOL://$COMMUNITY_HOST/dlt diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 580123a75..80ef55d39 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -216,7 +216,7 @@ log_step "====================================================================== export DLT_NGINX_CONF="${DLT_NGINX_CONF:-# dlt disabled}" # prepare inspector and gradido dlt node nginx config blocks if enabled -if [ "$DLT_CONNECTOR" = true ] ; then +if [ "$DLT_ACTIVE" = true ] ; then log_step "prepare inspector and dlt gradido node nginx config block" envsubst '$DLT_NODE_SERVER_PORT' < $NGINX_CONFIG_DIR/gradido-dlt.conf.template >> $NGINX_CONFIG_DIR/gradido-dlt.conf export DLT_NGINX_CONF=$(< $NGINX_CONFIG_DIR/gradido-dlt.conf) @@ -256,7 +256,7 @@ MODULES=( dht-node federation ) -if [ "$DLT_CONNECTOR" = true ] ; then +if [ "$DLT_ACTIVE" = true ] ; then MODULES+=("inspector") MODULES+=("dlt-connector") fi @@ -306,7 +306,7 @@ log_step 'build all modules' turbo build --env-mode=loose --concurrency=$(nproc) # build inspector and dlt-connector -if [ "$DLT_CONNECTOR" = true ]; then +if [ "$DLT_ACTIVE" = true ]; then log_step 'build inspector' cd $PROJECT_ROOT/inspector bun install @@ -339,7 +339,7 @@ pm2 start --name gradido-backend \ -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log \ --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' -if [ "$DLT_CONNECTOR" = true ] ; then +if [ "$DLT_ACTIVE" = true ] ; then pm2 start --name dlt-connector \ "env TZ=UTC NODE_ENV=production bun ./build/index.js" \ --cwd $PROJECT_ROOT/dlt-connector \ diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue index e749d0cd9..a33933907 100755 --- a/frontend/src/components/ContentFooter.vue +++ b/frontend/src/components/ContentFooter.vue @@ -43,6 +43,13 @@ {{ $t('navigation.support') }} + + {{ $t('footer.inspector') }} + diff --git a/frontend/src/config/schema.js b/frontend/src/config/schema.js index c7f7817b8..745e24b74 100644 --- a/frontend/src/config/schema.js +++ b/frontend/src/config/schema.js @@ -9,6 +9,7 @@ import { COMMUNITY_URL, DEBUG, DECAY_START_TIME, + DLT_ACTIVE, GMS_ACTIVE, GRAPHQL_URI, HUMHUB_ACTIVE, @@ -30,6 +31,7 @@ module.exports = Joi.object({ COMMUNITY_URL, DEBUG, DECAY_START_TIME, + DLT_ACTIVE, GMS_ACTIVE, GRAPHQL_URI, HUMHUB_ACTIVE, diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index e7741f83d..bf1fc818f 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -158,6 +158,7 @@ "year": "© {year}" }, "imprint": "Impressum", + "inspector": "Inspektor (experimentell)", "privacy_policy": "Datenschutzerklärung", "short_hash": "({shortHash})", "whitepaper": "Whitepaper" diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index d0ab23d1f..8739f322d 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -158,6 +158,7 @@ "year": "© {year}" }, "imprint": "Legal notice", + "inspector": "Inspector (experimental)", "privacy_policy": "Privacy policy", "short_hash": "({shortHash})", "whitepaper": "Whitepaper" diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index 9a0d4283f..5d0fcfe4c 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -140,6 +140,7 @@ "year": "© {year}" }, "imprint": "Aviso legal", + "inspector": "Inspector (experimental)", "privacy_policy": "Protección de Datos", "short_hash": "({shortHash})", "whitepaper": "Whitepaper" diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 55bdf4ee3..0488efe13 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -145,6 +145,7 @@ "year": "© {year}" }, "imprint": "Notification légale", + "inspector": "Inspecteur (expérimental)", "privacy_policy": "Politique de confidentialité", "short_hash": "({shortHash})", "whitepaper": "Papier blanc" diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index 9b3f3d265..fb264d54e 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -140,6 +140,7 @@ "year": "© {year}" }, "imprint": "Colofon", + "inspector": "Inspecteur (experimenteel)", "privacy_policy": "Privacyverklaring", "short_hash": "({shortHash})", "whitepaper": "Witboek" diff --git a/frontend/vite.config.mjs b/frontend/vite.config.mjs index 4a0674b0f..d722601d0 100644 --- a/frontend/vite.config.mjs +++ b/frontend/vite.config.mjs @@ -114,6 +114,7 @@ export default defineConfig(async ({ command }) => { AUTO_POLL_INTERVAL: CONFIG.AUTO_POLL_INTERVAL, BUILD_COMMIT: CONFIG.BUILD_COMMIT, CROSS_TX_REDEEM_LINK_ACTIVE: CONFIG.CROSS_TX_REDEEM_LINK_ACTIVE, + DLT_ACTIVE: CONFIG.DLT_ACTIVE, GMS_ACTIVE: CONFIG.GMS_ACTIVE, HUMHUB_ACTIVE: CONFIG.HUMHUB_ACTIVE, DEFAULT_PUBLISHER_ID: null, From f5d39f39c4926b0521ac73816501fbb443f5efaa Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 11:05:50 +0100 Subject: [PATCH 154/226] update missed env name change --- backend/.env.dist | 2 +- backend/.env.org | 2 +- backend/.env.template | 2 +- .../src/apis/dltConnector/DltConnectorClient.test.ts | 8 ++++---- backend/src/apis/dltConnector/DltConnectorClient.ts | 2 +- .../apis/dltConnector/__mocks__/DltConnectorClient.ts | 2 +- backend/src/apis/dltConnector/index.ts | 10 +++++----- .../graphql/resolver/TransactionLinkResolver.test.ts | 2 +- .../src/graphql/resolver/TransactionResolver.test.ts | 2 +- backend/src/graphql/resolver/UserResolver.test.ts | 2 +- backend/src/graphql/resolver/semaphore.test.ts | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 0860b9c94..f9fcb035f 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -22,7 +22,7 @@ KLICKTIPP_APIKEY_DE=SomeFakeKeyDE KLICKTIPP_APIKEY_EN=SomeFakeKeyEN # DltConnector -DLT_CONNECTOR=true +DLT_ACTIVE=false DLT_CONNECTOR_URL=http://localhost:6010 # Community diff --git a/backend/.env.org b/backend/.env.org index 2267fdc50..d352693a6 100644 --- a/backend/.env.org +++ b/backend/.env.org @@ -22,7 +22,7 @@ KLICKTIPP_APIKEY_DE=SomeFakeKeyDE KLICKTIPP_APIKEY_EN=SomeFakeKeyEN # DltConnector -DLT_CONNECTOR=true +DLT_ACTIVE=true DLT_CONNECTOR_URL=http://localhost:6010 # Community diff --git a/backend/.env.template b/backend/.env.template index 5212d1e1b..98090546d 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -24,7 +24,7 @@ KLICKTIPP_APIKEY_DE=$KLICKTIPP_APIKEY_DE KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN # DltConnector -DLT_CONNECTOR=$DLT_CONNECTOR +DLT_ACTIVE=$DLT_ACTIVE DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT # Community diff --git a/backend/src/apis/dltConnector/DltConnectorClient.test.ts b/backend/src/apis/dltConnector/DltConnectorClient.test.ts index e3673791b..55acb6e04 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.test.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.test.ts @@ -5,17 +5,17 @@ import { DltConnectorClient } from './DltConnectorClient' describe('undefined DltConnectorClient', () => { it('invalid url', () => { CONFIG.DLT_CONNECTOR_URL = '' - CONFIG.DLT_CONNECTOR = true + CONFIG.DLT_ACTIVE = true const result = DltConnectorClient.getInstance() expect(result).toBeUndefined() CONFIG.DLT_CONNECTOR_URL = 'http://dlt-connector:6010' }) - it('DLT_CONNECTOR is false', () => { - CONFIG.DLT_CONNECTOR = false + it('DLT_ACTIVE is false', () => { + CONFIG.DLT_ACTIVE = false const result = DltConnectorClient.getInstance() expect(result).toBeUndefined() - CONFIG.DLT_CONNECTOR = true + CONFIG.DLT_ACTIVE = true }) }) diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index a5e162ba0..2a1ced85d 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -31,7 +31,7 @@ export class DltConnectorClient { * just one instance of each subclass around. */ public static getInstance(): DltConnectorClient | undefined { - if (!CONFIG.DLT_CONNECTOR || !CONFIG.DLT_CONNECTOR_URL) { + if (!CONFIG.DLT_ACTIVE || !CONFIG.DLT_CONNECTOR_URL) { logger.info(`dlt-connector are disabled via config...`) return } diff --git a/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts b/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts index 81a7c5398..5a2c96d79 100644 --- a/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/__mocks__/DltConnectorClient.ts @@ -30,7 +30,7 @@ export class DltConnectorClient { * just one instance of each subclass around. */ public static getInstance(): DltConnectorClient | undefined { - if (!CONFIG.DLT_CONNECTOR || !CONFIG.DLT_CONNECTOR_URL) { + if (!CONFIG.DLT_ACTIVE || !CONFIG.DLT_CONNECTOR_URL) { logger.info(`dlt-connector are disabled via config...`) return } diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index bce319674..dd192b82c 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -64,7 +64,7 @@ async function executeDltTransaction(draft: TransactionDraft | null, typeId: Dlt * and update dltTransactionId of transaction in db with hiero transaction id */ export async function registerAddressTransaction(user: DbUser, community: DbCommunity): Promise { - if (!CONFIG.DLT_CONNECTOR) { + if (!CONFIG.DLT_ACTIVE) { return Promise.resolve(null) } if (!user.id) { @@ -88,7 +88,7 @@ export async function contributionTransaction( signingUser: DbUser, createdAt: Date, ): Promise { - if (!CONFIG.DLT_CONNECTOR) { + if (!CONFIG.DLT_ACTIVE) { return Promise.resolve(null) } const homeCommunity = await getHomeCommunity() @@ -107,7 +107,7 @@ export async function transferTransaction( memo: string, createdAt: Date ): Promise { - if (!CONFIG.DLT_CONNECTOR) { + if (!CONFIG.DLT_ACTIVE) { return Promise.resolve(null) } // load community if not already loaded, maybe they are remote communities @@ -125,7 +125,7 @@ export async function transferTransaction( export async function deferredTransferTransaction(senderUser: DbUser, transactionLink: DbTransactionLink) : Promise { - if (!CONFIG.DLT_CONNECTOR) { + if (!CONFIG.DLT_ACTIVE) { return Promise.resolve(null) } // load community if not already loaded @@ -138,7 +138,7 @@ export async function deferredTransferTransaction(senderUser: DbUser, transactio export async function redeemDeferredTransferTransaction(transactionLink: DbTransactionLink, amount: string, createdAt: Date, recipientUser: DbUser) : Promise { - if (!CONFIG.DLT_CONNECTOR) { + if (!CONFIG.DLT_ACTIVE) { return Promise.resolve(null) } // load user and communities if not already loaded diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index b6abcb0b2..18eb9dde6 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -43,7 +43,7 @@ const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) jest.mock('@/password/EncryptorUtils') -CONFIG.DLT_CONNECTOR = false +CONFIG.DLT_ACTIVE = false // mock semaphore to allow use fake timers jest.mock('database/src/util/TRANSACTIONS_LOCK') diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index a134ca84b..44c10deb9 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -38,7 +38,7 @@ import { CONFIG } from '@/config' jest.mock('@/password/EncryptorUtils') const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`) -CONFIG.DLT_CONNECTOR = false +CONFIG.DLT_ACTIVE = false CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index cee570c94..aaa7bcca9 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -117,7 +117,7 @@ beforeAll(async () => { query = testEnv.query con = testEnv.con CONFIG.HUMHUB_ACTIVE = false - CONFIG.DLT_CONNECTOR = false + CONFIG.DLT_ACTIVE = false await cleanDB() }) diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index d0bf08b7c..dce6354ef 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -26,7 +26,7 @@ import { TRANSACTIONS_LOCK } from 'database' jest.mock('@/password/EncryptorUtils') -CONFIG.DLT_CONNECTOR = false +CONFIG.DLT_ACTIVE = false CONFIG.EMAIL = false let mutate: ApolloServerTestClient['mutate'] From 700c5a5c2197ee3c79fb376dfad5e65da7e83cf6 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 11:20:45 +0100 Subject: [PATCH 155/226] fix bugs --- docker-compose.override.yml | 1 + frontend/src/components/ContentFooter.spec.js | 2 ++ frontend/src/components/ContentFooter.vue | 8 +++----- frontend/src/config/index.js | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 3898f9991..e49d45a1c 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -228,6 +228,7 @@ volumes: node_modules_frontend: node_modules_backend: node_modules_federation: + node_modules_inspector: node_modules_database: node_modules_dlt_connector: turbo_cache: diff --git a/frontend/src/components/ContentFooter.spec.js b/frontend/src/components/ContentFooter.spec.js index 1fca50af2..418c2c580 100644 --- a/frontend/src/components/ContentFooter.spec.js +++ b/frontend/src/components/ContentFooter.spec.js @@ -4,6 +4,8 @@ import ContentFooter from './ContentFooter' import CONFIG from '@/config' import { BCol, BNav, BNavItem, BRow } from 'bootstrap-vue-next' +console.log(`CONFIG in ContentFooter.spec.js: ${JSON.stringify(CONFIG, null, 2)}`) + describe('ContentFooter', () => { let wrapper diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue index a33933907..d6f120e49 100755 --- a/frontend/src/components/ContentFooter.vue +++ b/frontend/src/components/ContentFooter.vue @@ -43,11 +43,7 @@ {{ $t('navigation.support') }} - + {{ $t('footer.inspector') }} @@ -61,6 +57,8 @@ import CONFIG from '@/config' export default { data() { return { + dltActive: CONFIG.DLT_ACTIVE, + communityUrl: CONFIG.COMMUNITY_URL, year: new Date().getFullYear(), version: CONFIG.APP_VERSION, hash: CONFIG.BUILD_COMMIT, diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index f75ef910f..6e64797cc 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -2,6 +2,7 @@ // The whole contents is exposed to the client // Load Package Details for some default values +const { DLT_ACTIVE } = require('config-schema') const pkg = require('../../package') const constants = { @@ -38,6 +39,7 @@ if (process.env.FRONTEND_HOSTING === 'nodejs') { // version.FRONTEND_MODULE_PORT const features = { + DLT_ACTIVE: process.env.DLT_ACTIVE === 'true', GMS_ACTIVE: process.env.GMS_ACTIVE === 'true', HUMHUB_ACTIVE: process.env.HUMHUB_ACTIVE === 'true', AUTO_POLL_INTERVAL: Number.parseInt(process.env.AUTO_POLL_INTERVAL ?? 0), From 8b7da5fd68bd43f34fa376b4d30a66598cb47153 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 11:22:52 +0100 Subject: [PATCH 156/226] remove debug console statement --- frontend/src/components/ContentFooter.spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/ContentFooter.spec.js b/frontend/src/components/ContentFooter.spec.js index 418c2c580..1fca50af2 100644 --- a/frontend/src/components/ContentFooter.spec.js +++ b/frontend/src/components/ContentFooter.spec.js @@ -4,8 +4,6 @@ import ContentFooter from './ContentFooter' import CONFIG from '@/config' import { BCol, BNav, BNavItem, BRow } from 'bootstrap-vue-next' -console.log(`CONFIG in ContentFooter.spec.js: ${JSON.stringify(CONFIG, null, 2)}`) - describe('ContentFooter', () => { let wrapper From 183d4fdc83cce765ba3587c85ca783a887845a50 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 11:25:33 +0100 Subject: [PATCH 157/226] remove accidently added line --- frontend/src/config/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 6e64797cc..d1d9966f8 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -2,7 +2,6 @@ // The whole contents is exposed to the client // Load Package Details for some default values -const { DLT_ACTIVE } = require('config-schema') const pkg = require('../../package') const constants = { From 07e2ba0bc8dcc568fad5d84b44534e81930ea98e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 12:36:08 +0100 Subject: [PATCH 158/226] fix wrong code --- core/src/emails/locales/en.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/emails/locales/en.json b/core/src/emails/locales/en.json index b76bc1497..fb90a0334 100644 --- a/core/src/emails/locales/en.json +++ b/core/src/emails/locales/en.json @@ -1,7 +1,4 @@ { - "accountMultiRegistration": { - "contactSupport": "accountMultiRegistration.contactSupport" - }, "emails": { "accountActivation": { "activateAccount": "Activate account", From c60569e9007586e322cd14740fa93ce84e3e2d7b Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 12:41:01 +0100 Subject: [PATCH 159/226] remove wrong line --- core/src/emails/sendEmailTranslated.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts index 30ae03112..2e5bcca93 100644 --- a/core/src/emails/sendEmailTranslated.ts +++ b/core/src/emails/sendEmailTranslated.ts @@ -113,7 +113,6 @@ export const sendEmailTranslated = async ({ }) .catch((error: unknown) => { logger.error('Error sending notification email', error) - throw error }) return resultSend From bad4b69868210397e8d1e4b335c7b02aee89c291 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 12:49:41 +0100 Subject: [PATCH 160/226] fix types without changing logic --- core/src/emails/sendEmailTranslated.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/emails/sendEmailTranslated.ts b/core/src/emails/sendEmailTranslated.ts index 2e5bcca93..205ca07c6 100644 --- a/core/src/emails/sendEmailTranslated.ts +++ b/core/src/emails/sendEmailTranslated.ts @@ -25,7 +25,7 @@ export const sendEmailTranslated = async ({ } template: string locals: Record -}): Promise | boolean | null> => { +}): Promise | boolean | null | Error> => { // TODO: test the calling order of 'i18n.setLocale' for example: language of logging 'en', language of email receiver 'es', reset language of current user 'de' if (!CONFIG.EMAIL) { @@ -113,6 +113,7 @@ export const sendEmailTranslated = async ({ }) .catch((error: unknown) => { logger.error('Error sending notification email', error) + return error }) return resultSend From 295eb525f0b7a247b21bd0739a212e1db3aa53b8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 12:51:57 +0100 Subject: [PATCH 161/226] adapt to change in sendEmailTranslated --- core/src/emails/sendEmailVariants.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/emails/sendEmailVariants.ts b/core/src/emails/sendEmailVariants.ts index da67beefb..8a4b6f9af 100644 --- a/core/src/emails/sendEmailVariants.ts +++ b/core/src/emails/sendEmailVariants.ts @@ -31,7 +31,7 @@ export const sendAddedContributionMessageEmail = ( data: EmailCommonData & ContributionEmailCommonData & { message: string }, -): Promise | boolean | null> => { +): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>`, @@ -48,7 +48,7 @@ export const sendAccountActivationEmail = (data: EmailCommonData & { activationLink: string timeDurationObject: Record logoUrl?: string | null -}): Promise | boolean | null> => { +}): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'accountActivation', @@ -59,7 +59,7 @@ export const sendAccountActivationEmail = (data: EmailCommonData & { }) } -export const sendAccountMultiRegistrationEmail = (data: EmailCommonData): Promise | boolean | null> => { +export const sendAccountMultiRegistrationEmail = (data: EmailCommonData): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'accountMultiRegistration', @@ -74,7 +74,7 @@ export const sendContributionConfirmedEmail = ( data: EmailCommonData & ContributionEmailCommonData & { contributionAmount: Decimal }, -): Promise | boolean | null> => { +): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionConfirmed', @@ -90,7 +90,7 @@ export const sendContributionChangedByModeratorEmail = ( data: EmailCommonData & ContributionEmailCommonData & { contributionMemoUpdated: string }, -): Promise | boolean | null> => { +): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionChangedByModerator', @@ -104,7 +104,7 @@ export const sendContributionChangedByModeratorEmail = ( export const sendContributionDeletedEmail = ( data: EmailCommonData & ContributionEmailCommonData, -): Promise | boolean | null> => { +): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionDeleted', @@ -117,7 +117,7 @@ export const sendContributionDeletedEmail = ( export const sendContributionDeniedEmail = ( data: EmailCommonData & ContributionEmailCommonData, -): Promise | boolean | null> => { +): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'contributionDenied', @@ -131,7 +131,7 @@ export const sendContributionDeniedEmail = ( export const sendResetPasswordEmail = (data: EmailCommonData & { resetLink: string timeDurationObject: Record -}): Promise | boolean | null> => { +}): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'resetPassword', @@ -148,7 +148,7 @@ export const sendTransactionLinkRedeemedEmail = (data: EmailCommonData & { senderEmail: string transactionMemo: string transactionAmount: Decimal -}): Promise | boolean | null> => { +}): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'transactionLinkRedeemed', @@ -166,7 +166,7 @@ export const sendTransactionReceivedEmail = (data: EmailCommonData & { senderEmail: string memo: string transactionAmount: Decimal -}): Promise | boolean | null> => { +}): Promise | boolean | null | Error> => { return sendEmailTranslated({ receiver: { to: `${data.firstName} ${data.lastName} <${data.email}>` }, template: 'transactionReceived', From 8e990314a122cc1de8a790896c48d7781232e621 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:04:26 +0100 Subject: [PATCH 162/226] fixed for future use of biome --- backend/src/apis/openai/OpenaiClient.ts | 1 + backend/src/graphql/resolver/TransactionResolver.test.ts | 1 - backend/src/seeds/factory/user.ts | 1 - config-schema/src/validate.ts | 1 + core/src/graphql/logic/storeLinkAsRedeemed.ts | 8 ++++++-- core/src/types/images.d.ts | 1 + database/src/queries/communityHandshakes.test.ts | 1 - .../graphql/api/1_0/resolver/AuthenticationResolver.ts | 2 ++ federation/src/server/cors.ts | 5 ++--- shared/src/helper/onShutdown.ts | 3 ++- 10 files changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/src/apis/openai/OpenaiClient.ts b/backend/src/apis/openai/OpenaiClient.ts index eb37a04f8..5655020aa 100644 --- a/backend/src/apis/openai/OpenaiClient.ts +++ b/backend/src/apis/openai/OpenaiClient.ts @@ -92,6 +92,7 @@ export class OpenaiClient { if (openaiThreadEntity.updatedAt < new Date(Date.now() - OPENAI_AI_THREAD_DEFAULT_TIMEOUT_DAYS * 24 * 60 * 60 * 1000)) { logger.info(`Openai thread for user: ${user.id} is older than ${OPENAI_AI_THREAD_DEFAULT_TIMEOUT_DAYS} days, deleting...`) // let run async, because it could need some time, but we don't need to wait, because we create a new one nevertheless + // biome-ignore lint/complexity/noVoid: start it intentionally async without waiting for result void this.deleteThread(openaiThreadEntity.id) return [] } diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 774502b28..636c4d63f 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -73,7 +73,6 @@ let peter: User let homeCom: DbCommunity let foreignCom: DbCommunity -let fedForeignCom: DbFederatedCommunity describe('send coins', () => { beforeAll(async () => { diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 44db02c8f..36d9adfeb 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -18,7 +18,6 @@ export const userFactory = async ( // console.log('call createUser with', JSON.stringify(user, null, 2)) const response = await mutate({ mutation: createUser, variables: user }) if (!response?.data?.createUser) { - // biome-ignore lint/suspicious/noConsole: will be used in tests where logging is mocked // console.log(JSON.stringify(response, null, 2)) throw new Error('createUser mutation returned unexpected response') } diff --git a/config-schema/src/validate.ts b/config-schema/src/validate.ts index 83cf097b3..17ccea483 100644 --- a/config-schema/src/validate.ts +++ b/config-schema/src/validate.ts @@ -31,6 +31,7 @@ export function validate(schema: ObjectSchema, data: any) { ) } } catch (e) { + // biome-ignore lint/suspicious/noConsole: schema validation may be run before logger is initialized console.error('Error getting description for key ' + key + ': ' + e) throw e } diff --git a/core/src/graphql/logic/storeLinkAsRedeemed.ts b/core/src/graphql/logic/storeLinkAsRedeemed.ts index cccc97d50..efc3589de 100644 --- a/core/src/graphql/logic/storeLinkAsRedeemed.ts +++ b/core/src/graphql/logic/storeLinkAsRedeemed.ts @@ -1,4 +1,8 @@ -import { TransactionLink as DbTransactionLink, User as DbUser } from "database"; +import { TransactionLink as DbTransactionLink, User as DbUser } from 'database' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY_NAME } from '../../config/const' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.logic.storeLinkAsRedeemed`) export async function storeLinkAsRedeemed( dbTransactionLink: DbTransactionLink, @@ -11,7 +15,7 @@ export async function storeLinkAsRedeemed( await DbTransactionLink.save(dbTransactionLink) return true } catch (err) { - console.error('error in storeLinkAsRedeemed;', err) + logger.error('error: ', err) return false } } \ No newline at end of file diff --git a/core/src/types/images.d.ts b/core/src/types/images.d.ts index ef7006d32..91c6fd6f9 100644 --- a/core/src/types/images.d.ts +++ b/core/src/types/images.d.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/style/noDefaultExport: Asset modules use default export by convention declare module '*.jpg' { const value: string export default value diff --git a/database/src/queries/communityHandshakes.test.ts b/database/src/queries/communityHandshakes.test.ts index 09937cc66..c1b665bab 100644 --- a/database/src/queries/communityHandshakes.test.ts +++ b/database/src/queries/communityHandshakes.test.ts @@ -58,7 +58,6 @@ describe('communityHandshakes', () => { communityHandshakeState!.status = CommunityHandshakeStateType.START_OPEN_CONNECTION_CALLBACK await communityHandshakeState!.save() const communityHandshakeState2 = await findPendingCommunityHandshake(publicKey, '1_0') - const states = await DbCommunityHandshakeState.find() expect(communityHandshakeState2).toBeDefined() expect(communityHandshakeState2).toMatchObject({ publicKey: publicKey.asBuffer(), diff --git a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts index d22c816ff..3bee91e3e 100644 --- a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts @@ -62,6 +62,7 @@ export class AuthenticationResolver { // no await to respond immediately and invoke callback-request asynchronously // important: startOpenConnectionCallback must catch all exceptions them self, or server will crash! + // biome-ignore lint/complexity/noVoid: start it intentionally async without waiting for result void startOpenConnectionCallback(args.handshakeID, argsPublicKey, fedComA) methodLogger.debug('openConnection() successfully initiated callback and returns true immediately...') return true @@ -96,6 +97,7 @@ export class AuthenticationResolver { `found fedComB and start authentication: ${fedComB.endPoint}${fedComB.apiVersion}`, ) // no await to respond immediately and invoke authenticate-request asynchronously + // biome-ignore lint/complexity/noVoid: start it intentionally async without waiting for result void startAuthentication(args.handshakeID, openConnectionCallbackJwtPayload.oneTimeCode, fedComB) // methodLogger.debug('openConnectionCallback() successfully initiated authentication and returns true immediately...') return true diff --git a/federation/src/server/cors.ts b/federation/src/server/cors.ts index 873d6a2eb..95663695d 100644 --- a/federation/src/server/cors.ts +++ b/federation/src/server/cors.ts @@ -1,9 +1,8 @@ -import cors from 'cors' +import corsLib from 'cors' const corsOptions = { origin: '*', exposedHeaders: ['token'], } -// biome-ignore lint/style/noDefaultExport: -export default cors(corsOptions) +export const cors = corsLib(corsOptions) diff --git a/shared/src/helper/onShutdown.ts b/shared/src/helper/onShutdown.ts index a27c931a6..ea24bf2fc 100644 --- a/shared/src/helper/onShutdown.ts +++ b/shared/src/helper/onShutdown.ts @@ -1,4 +1,3 @@ -import { Logger } from 'log4js' import colors from 'yoctocolors-cjs' export enum ShutdownReason { @@ -44,8 +43,10 @@ export function onShutdown(shutdownHandler: (reason: ShutdownReason, error?: Err } export function printServerCrashAsciiArt(msg1: string, msg2: string, msg3: string) { + // biome-ignore-start lint/suspicious/noConsole: Server Crash Ascii Art is for console and stdout console.error(colors.redBright(` /\\_/\\ ${msg1}`)) console.error(colors.redBright(`( x.x ) ${msg2}`)) console.error(colors.redBright(` > < ${msg3}`)) console.error(colors.redBright('')) + // biome-ignore-end lint/suspicious/noConsole: Server Crash Ascii Art is for console and stdout } \ No newline at end of file From bcaf1cdbe2caeb3e802a9464abb218e39bcdfd22 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:07:13 +0100 Subject: [PATCH 163/226] adapt to logic change --- federation/src/server/createServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/federation/src/server/createServer.ts b/federation/src/server/createServer.ts index 015fbba48..d8cb0f473 100644 --- a/federation/src/server/createServer.ts +++ b/federation/src/server/createServer.ts @@ -4,7 +4,7 @@ import { ApolloServer } from 'apollo-server-express' import express, { Express } from 'express' // server -import cors from './cors' +import { cors } from './cors' // import serverContext from './context' import { plugins } from './plugins' From 388c7a795cd4112801c77c121d0b04f3eb1f949d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:45:06 +0100 Subject: [PATCH 164/226] add new env to frontend env template --- frontend/.env.template | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/.env.template b/frontend/.env.template index 9c51e03ca..4fa775098 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -23,4 +23,5 @@ META_KEYWORDS_EN=$META_KEYWORDS_EN META_AUTHOR=$META_AUTHOR GMS_ACTIVE=$GMS_ACTIVE -HUMHUB_ACTIVE=$HUMHUB_ACTIVE \ No newline at end of file +HUMHUB_ACTIVE=$HUMHUB_ACTIVE +DLT_ACTIVE=$DLT_ACTIVE \ No newline at end of file From f91dd859bf7406f0b89c120084ae4627941bd7b8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:48:16 +0100 Subject: [PATCH 165/226] fix link --- frontend/src/components/ContentFooter.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue index d6f120e49..55299d786 100755 --- a/frontend/src/components/ContentFooter.vue +++ b/frontend/src/components/ContentFooter.vue @@ -43,7 +43,7 @@ {{ $t('navigation.support') }} - + {{ $t('footer.inspector') }} From dc8a8181b430bd94c95474fcbae8aabc97d235bd Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 15:31:04 +0100 Subject: [PATCH 166/226] change default dlt connector url to localhost --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 9a57fed43..ddad28582 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -42,7 +42,7 @@ const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNIT const DLT_CONNECTOR_PORT = process.env.DLT_CONNECTOR_PORT ?? 6010 const dltConnector = { - DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `${COMMUNITY_URL}:${DLT_CONNECTOR_PORT}`, + DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `http://localhost:${DLT_CONNECTOR_PORT}`, } const community = { From 1ead1bc4a83a0fc2c38cd3e7d0c77c96ecb25913 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 22:55:27 +0100 Subject: [PATCH 167/226] correct errors after master merge --- bun.lock | 436 ++++++++++---------- core/src/emails/sendEmailTranslated.test.ts | 2 +- core/src/emails/sendEmailVariants.test.ts | 3 +- 3 files changed, 211 insertions(+), 230 deletions(-) diff --git a/bun.lock b/bun.lock index d9c5cd24d..5b80668dd 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "gradido", @@ -296,6 +295,7 @@ "version": "2.7.1", "dependencies": { "cross-env": "^7.0.3", + "email-templates": "^10.0.1", "redis-semaphore": "^5.6.2", "sodium-native": "^3.4.1", }, @@ -496,27 +496,27 @@ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], - "@aws-sdk/client-ses": ["@aws-sdk/client-ses@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/credential-provider-node": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-2toHYwRkcYGasPHYGwOwaIAa2Api/uFhmL3px0Tyt4bne2ilqhSwq+6a/0UVMd8JYwWaLMJolTbWKFt2jUlmGg=="], + "@aws-sdk/client-ses": ["@aws-sdk/client-ses@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-aAtz0+q24AJSLOHF6JHaFZ/z/0gdEJI7GRjBo+Zb//GK8wkfMCHtFkA61Kxn3kB3nrZBJmWVQ8dX3hw4vhUAaA=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-0G73S2cDqYwJVvqL08eakj79MZG2QRaB56Ul8/Ps9oQxllr7DMI1IQ/N3j3xjxgpq/U36pkoFZ8aK1n7Sbr3IQ=="], + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], - "@aws-sdk/core": ["@aws-sdk/core@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eGJ2ySUMvgtOziHhDRDLCrj473RJoL4J1vPjVM3NrKC/fF3/LoHjkut8AAnKmrW6a2uTzNKubigw8dEnpmpERw=="], + "@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-dKajFuaugEA5i9gCKzOaVy9uTeZcApE+7Z5wdcZ6j40523fY1a56khDAUYkCfwqa7sHci4ccmxBkAo+fW1RChA=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-5FguODLXG1tWx/x8fBxH+GVrk7Hey2LbXV5h9SFzYCx/2h50URBm0+9hndg0Rd23+xzYe14F6SI9HA9c1sPnjg=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/credential-provider-env": "3.936.0", "@aws-sdk/credential-provider-http": "3.936.0", "@aws-sdk/credential-provider-login": "3.936.0", "@aws-sdk/credential-provider-process": "3.936.0", "@aws-sdk/credential-provider-sso": "3.936.0", "@aws-sdk/credential-provider-web-identity": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-TbUv56ERQQujoHcLMcfL0Q6bVZfYF83gu/TjHkVkdSlHPOIKaG/mhE2XZSQzXv1cud6LlgeBbfzVAxJ+HPpffg=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8DVrdRqPyUU66gfV7VZNToh56ZuO5D6agWrkLQE/xbLJOm2RbeRgh6buz7CqV8ipRd6m+zCl9mM4F3osQLZn8Q=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.936.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.936.0", "@aws-sdk/credential-provider-http": "3.936.0", "@aws-sdk/credential-provider-ini": "3.936.0", "@aws-sdk/credential-provider-process": "3.936.0", "@aws-sdk/credential-provider-sso": "3.936.0", "@aws-sdk/credential-provider-web-identity": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-rk/2PCtxX9xDsQW8p5Yjoca3StqmQcSfkmD7nQ61AqAHL1YgpSQWqHE+HjfGGiHDYKG7PvE33Ku2GyA7lEIJAw=="], + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GpA4AcHb96KQK2PSPUyvChvrsEKiLhQ5NWjeef2IZ3Jc8JoosiedYqp6yhZR+S8cTysuvx56WyJIJc8y8OTrLA=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.936.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.936.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/token-providers": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wHlEAJJvtnSyxTfNhN98JcU4taA1ED2JvuI2eePgawqBwS/Tzi0mhED1lvNIaWOkjfLd+nHALwszGrtJwEq4yQ=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-v3qHAuoODkoRXsAF4RG+ZVO6q2P9yYBT4GMpMEfU9wXVNn7AIfwZgTwzSUfnjNiGva5BKleWVpRpJ9DeuLFbUg=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], @@ -524,13 +524,13 @@ "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-YB40IPa7K3iaYX0lSnV9easDOLPLh+fJyUDF3BH8doX4i1AOSsYn86L4lVldmOaSX+DwiaqKHpvk4wPBdcIPWw=="], + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.936.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eyj2tz1XmDSLSZQ5xnB7cLTVKkSJnYAEoNDSUNhzWPxrBDYeJzIbatecOKceKCU8NBf8gWWZCK/CSY0mDxMO0A=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.936.0", "", { "dependencies": { "@aws-sdk/core": "3.936.0", "@aws-sdk/nested-clients": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-vvw8+VXk0I+IsoxZw0mX9TMJawUJvEsg3EF7zcCSetwhNPAU8Xmlhv7E/sN/FgSmm7b7DsqKoW6rVtQiCs1PWQ=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg=="], "@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], @@ -540,7 +540,7 @@ "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.936.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.936.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-XOEc7PF9Op00pWV2AYCGDSu5iHgYjIO53Py2VUQTIvP7SRCaCsXmA33mjBvC2Ms6FhSyWNa4aK4naUGIz0hQcw=="], + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], @@ -548,11 +548,11 @@ "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="], + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], - "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], - "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], @@ -566,13 +566,13 @@ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], @@ -612,9 +612,9 @@ "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], @@ -638,11 +638,9 @@ "@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="], - "@cacheable/memoize": ["@cacheable/memoize@2.0.3", "", { "dependencies": { "@cacheable/utils": "^2.0.3" } }, "sha512-hl9wfQgpiydhQEIv7fkjEzTGE+tcosCXLKFDO707wYJ/78FVOlowb36djex5GdbSyeHnG62pomYLMuV/OT8Pbw=="], + "@cacheable/memory": ["@cacheable/memory@2.0.5", "", { "dependencies": { "@cacheable/utils": "^2.3.0", "@keyv/bigmap": "^1.1.0", "hookified": "^1.12.2", "keyv": "^5.5.4" } }, "sha512-fkiAxCvssEyJZ5fxX4tcdZFRmW9JehSTGvvqmXn6rTzG5cH6V/3C4ad8yb01vOjp2xBydHkHrgpW0qeGtzt6VQ=="], - "@cacheable/memory": ["@cacheable/memory@2.0.3", "", { "dependencies": { "@cacheable/memoize": "^2.0.3", "@cacheable/utils": "^2.0.3", "@keyv/bigmap": "^1.0.2", "hookified": "^1.12.1", "keyv": "^5.5.3" } }, "sha512-R3UKy/CKOyb1LZG/VRCTMcpiMDyLH7SH3JrraRdK6kf3GweWCOU3sgvE13W3TiDRbxnDKylzKJvhUAvWl9LQOA=="], - - "@cacheable/utils": ["@cacheable/utils@2.1.0", "", { "dependencies": { "keyv": "^5.5.3" } }, "sha512-ZdxfOiaarMqMj+H7qwlt5EBKWaeGihSYVHdQv5lUsbn8MJJOTW82OIwirQ39U5tMZkNvy3bQE+ryzC+xTAb9/g=="], + "@cacheable/utils": ["@cacheable/utils@2.3.1", "", { "dependencies": { "hashery": "^1.2.0", "keyv": "^5.5.4" } }, "sha512-38NJXjIr4W1Sghun8ju+uYWD8h2c61B4dKwfnQHVDFpAJ9oS28RpfqZQJ6Dgd3RceGkILDY9YT+72HJR3LoeSQ=="], "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], @@ -662,61 +660,61 @@ "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@eslint/eslintrc": ["@eslint/eslintrc@1.4.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", "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" } }, "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA=="], @@ -742,19 +740,19 @@ "@hyperswarm/secret-stream": ["@hyperswarm/secret-stream@6.9.1", "", { "dependencies": { "b4a": "^1.1.0", "hypercore-crypto": "^3.3.1", "noise-curve-ed": "^2.0.1", "noise-handshake": "^4.0.0", "sodium-secretstream": "^1.1.0", "sodium-universal": "^5.0.0", "streamx": "^2.14.0", "timeout-refresh": "^2.0.0", "unslab": "^1.3.0" } }, "sha512-xb0S5y3YJwBakD77JOGBHlBxdp63mHClZoXBYoLv+9wH8e054ESKlmQptWqjJK5dv5VMUIVYOJB4MaOpB0JdGw=="], - "@iconify-json/arcticons": ["@iconify-json/arcticons@1.2.38", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-AnPvt17WFSGkakgWHRobIrRi1SEPmpzRAoOn6SokwoaItBzjUcgvRNW/GDuh/PWZwI5T4+VRJaBmB4Owa1Cktw=="], + "@iconify-json/arcticons": ["@iconify-json/arcticons@1.2.39", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-MUrn2tTlCa73LFO740sD29BPXVpiHR9PYg8zD7KQzKe0y63m58HzNvNqeoWPG4oNZ7NvNlhYhsCHpAsmKpaToA=="], "@iconify-json/bi": ["@iconify-json/bi@1.2.6", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-fWfLr1/+DJDe8+rIUXxMwvmWBZFlxRtM59sYnrezJ2xX87QKyXVw3QuforJ4kF2Orrz85J+JTRG6305vaJ7flA=="], "@iconify-json/fa": ["@iconify-json/fa@1.2.2", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-Rw0L97uO3W0Gy2rq4cM/TH3QjzuPuRca1F2steumZ57zOeheGQdiqo50O6KHjm+WgImmV92IFPUTU6eiaJsrTw=="], - "@iconify-json/humbleicons": ["@iconify-json/humbleicons@1.2.12", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-RPD+hBExPr+r+AcunJH/NYrtFNBm/99HjhGlaMDxIXh5RMqD7HebE5oJS6TgrNoUHHuQZ2u1gHmg4vgjaptB+A=="], + "@iconify-json/humbleicons": ["@iconify-json/humbleicons@1.2.16", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-z/OBrwW1DbtZ0me3H/qxV/Pw+ze5UrJnDhrlgI394DoIW8HGqxmIALBLpaYDYSHyH5gywZOz4K2y4O6C4uQNZQ=="], "@iconify-json/ion": ["@iconify-json/ion@1.2.6", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-JftEXKfjvJNn3SrGeSBrG/waRkjeTpLdMLNLwpAX4NgI14QgJoAeXEh2iZjNPqioAkeIgErX4Bi6mnFwpjk3BQ=="], "@iconify-json/mdi": ["@iconify-json/mdi@1.2.3", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-O3cLwbDOK7NNDf2ihaQOH5F9JglnulNDFV7WprU2dSoZu3h3cWH//h74uQAB87brHmvFVxIOkuBX2sZSzYhScg=="], - "@iconify/json": ["@iconify/json@2.2.398", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.0" } }, "sha512-SEUDjkyAenAKMd5hDfzNzeObZw+KgQdIHaOuWA4yv89qSf2s0dJ7L1iXhRjtEZxFnuXQ2D67uFiHmE+90jvDGQ=="], + "@iconify/json": ["@iconify/json@2.2.410", "", { "dependencies": { "@iconify/types": "*", "pathe": "^2.0.3" } }, "sha512-0IhW9Sfudf3cPQHoCwr2gJMMUUkLW01WIkGoP9PbwVKXl1I/KTRHtM9IchLufT8M86QHBWRcinApzkL60TH9vA=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], @@ -762,11 +760,11 @@ "@intlify/bundle-utils": ["@intlify/bundle-utils@10.0.1", "", { "dependencies": { "@intlify/message-compiler": "^11.1.2", "@intlify/shared": "^11.1.2", "acorn": "^8.8.2", "escodegen": "^2.1.0", "estree-walker": "^2.0.2", "jsonc-eslint-parser": "^2.3.0", "mlly": "^1.2.0", "source-map-js": "^1.0.1", "yaml-eslint-parser": "^1.2.2" } }, "sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ=="], - "@intlify/core-base": ["@intlify/core-base@9.13.1", "", { "dependencies": { "@intlify/message-compiler": "9.13.1", "@intlify/shared": "9.13.1" } }, "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w=="], + "@intlify/core-base": ["@intlify/core-base@9.14.5", "", { "dependencies": { "@intlify/message-compiler": "9.14.5", "@intlify/shared": "9.14.5" } }, "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA=="], "@intlify/eslint-plugin-vue-i18n": ["@intlify/eslint-plugin-vue-i18n@1.4.1", "", { "dependencies": { "@eslint/eslintrc": "^1.2.0", "@intlify/core-base": "^9.1.9", "@intlify/message-compiler": "^9.1.9", "debug": "^4.3.1", "glob": "^7.1.3", "ignore": "^5.0.5", "is-language-code": "^3.1.0", "js-yaml": "^4.0.0", "json5": "^2.1.3", "jsonc-eslint-parser": "^2.0.0", "lodash": "^4.17.11", "parse5": "^6.0.0", "semver": "^7.3.4", "vue-eslint-parser": "^8.0.0", "yaml-eslint-parser": "^0.5.0" }, "peerDependencies": { "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-vnhwxcUTYCL/tCeBkXMDz959DVHNaDd3SRt3jdyX5ZwHaSSx93aD7kZV7ZmJpq4lZlq7Q1eVRGhpmpTNGdvU9w=="], - "@intlify/message-compiler": ["@intlify/message-compiler@9.13.1", "", { "dependencies": { "@intlify/shared": "9.13.1", "source-map-js": "^1.0.2" } }, "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w=="], + "@intlify/message-compiler": ["@intlify/message-compiler@9.14.5", "", { "dependencies": { "@intlify/shared": "9.14.5", "source-map-js": "^1.0.2" } }, "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ=="], "@intlify/shared": ["@intlify/shared@9.13.1", "", {}, "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ=="], @@ -828,7 +826,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@keyv/bigmap": ["@keyv/bigmap@1.1.0", "", { "dependencies": { "hookified": "^1.12.2" }, "peerDependencies": { "keyv": "^5.5.3" } }, "sha512-MX7XIUNwVRK+hjZcAbNJ0Z8DREo+Weu9vinBOjGU1thEi9F6vPhICzBbk4CCf3eEefKRz7n6TfZXwUFZTSgj8Q=="], + "@keyv/bigmap": ["@keyv/bigmap@1.3.0", "", { "dependencies": { "hashery": "^1.2.0", "hookified": "^1.13.0" }, "peerDependencies": { "keyv": "^5.5.4" } }, "sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg=="], "@keyv/serialize": ["@keyv/serialize@1.1.1", "", {}, "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA=="], @@ -844,7 +842,7 @@ "@messageformat/parser": ["@messageformat/parser@5.1.1", "", { "dependencies": { "moo": "^0.5.1" } }, "sha512-3p0YRGCcTUCYvBKLIxtDDyrJ0YijGIwrTRu1DT8gIviIDZru8H23+FkY6MJBzM1n9n20CiM4VeDYuBsrrwnLjg=="], - "@messageformat/runtime": ["@messageformat/runtime@3.0.1", "", { "dependencies": { "make-plural": "^7.0.0" } }, "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg=="], + "@messageformat/runtime": ["@messageformat/runtime@3.0.2", "", { "dependencies": { "make-plural": "^7.0.0" } }, "sha512-dkIPDCjXcfhSHgNE1/qV6TeczQZR59Yx0xXeafVKgK3QVWoxc38ljwpksUpnzCGvN151KUbCJTDZVmahtf1YZw=="], "@morev/utils": ["@morev/utils@3.13.1", "", { "dependencies": { "fast-copy": "^3.0.2", "fast-equals": "^5.0.1", "ohash": "^1.1.4", "type-fest": "^4.26.1" } }, "sha512-dNsXp9Ef9cuPIGmL6igYQx0VeHPoZQ9Kp6M7lLnJ2WglMFpoy5gNw2WAldquEsJ0m+sR1DTOLfrSpWvF/wMVDw=="], @@ -892,7 +890,7 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@nuxt/kit": ["@nuxt/kit@3.19.3", "", { "dependencies": { "c12": "^3.3.0", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.2", "std-env": "^3.9.0", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "unimport": "^5.4.1", "untyped": "^2.0.0" } }, "sha512-ze46EW5xW+UxDvinvPkYt2MzR355Az1lA3bpX8KDialgnCwr+IbkBij/udbUEC6ZFbidPkfK1eKl4ESN7gMY+w=="], + "@nuxt/kit": ["@nuxt/kit@3.20.1", "", { "dependencies": { "c12": "^3.3.1", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "untyped": "^2.0.0" } }, "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA=="], "@one-ini/wasm": ["@one-ini/wasm@0.1.1", "", {}, "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="], @@ -952,49 +950,49 @@ "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.5", "", { "os": "android", "cpu": "arm" }, "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.5", "", { "os": "android", "cpu": "arm64" }, "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.5", "", { "os": "linux", "cpu": "arm" }, "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.5", "", { "os": "linux", "cpu": "none" }, "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.5", "", { "os": "none", "cpu": "arm64" }, "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.5", "", { "os": "win32", "cpu": "x64" }, "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], @@ -1098,29 +1096,29 @@ "@sqltools/formatter": ["@sqltools/formatter@1.2.5", "", {}, "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw=="], - "@swc/cli": ["@swc/cli@0.7.8", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3", "tinyglobby": "^0.2.13" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-27Ov4rm0s2C6LLX+NDXfDVB69LGs8K94sXtFhgeUyQ4DBywZuCgTBu2loCNHRr8JhT9DeQvJM5j9FAu/THbo4w=="], + "@swc/cli": ["@swc/cli@0.7.9", "", { "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", "commander": "^8.3.0", "minimatch": "^9.0.3", "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3", "tinyglobby": "^0.2.13" }, "peerDependencies": { "@swc/core": "^1.2.66", "chokidar": "^4.0.1" }, "optionalPeers": ["chokidar"], "bin": { "swc": "bin/swc.js", "swcx": "bin/swcx.js", "spack": "bin/spack.js" } }, "sha512-AFQu3ZZ9IcdClTknxbug08S9ed/q8F3aYkO5NoZ+6IjQ5UEo1s2HN1GRKNvUslYx2EoVYxd+6xGcp6C7wwtxyQ=="], - "@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="], + "@swc/core": ["@swc/core@1.15.3", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.3", "@swc/core-darwin-x64": "1.15.3", "@swc/core-linux-arm-gnueabihf": "1.15.3", "@swc/core-linux-arm64-gnu": "1.15.3", "@swc/core-linux-arm64-musl": "1.15.3", "@swc/core-linux-x64-gnu": "1.15.3", "@swc/core-linux-x64-musl": "1.15.3", "@swc/core-win32-arm64-msvc": "1.15.3", "@swc/core-win32-ia32-msvc": "1.15.3", "@swc/core-win32-x64-msvc": "1.15.3" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q=="], - "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ=="], + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ=="], - "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.13.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng=="], + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A=="], - "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.13.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ=="], + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.3", "", { "os": "linux", "cpu": "arm" }, "sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg=="], - "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw=="], + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw=="], - "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ=="], + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g=="], - "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA=="], + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.3", "", { "os": "linux", "cpu": "x64" }, "sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A=="], - "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q=="], + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.3", "", { "os": "linux", "cpu": "x64" }, "sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug=="], - "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.13.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw=="], + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA=="], - "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.13.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw=="], + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw=="], - "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.13.5", "", { "os": "win32", "cpu": "x64" }, "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q=="], + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.3", "", { "os": "win32", "cpu": "x64" }, "sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog=="], "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], @@ -1138,7 +1136,7 @@ "@tootallnate/once": ["@tootallnate/once@1.1.2", "", {}, "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="], - "@tsconfig/node10": ["@tsconfig/node10@1.0.11", "", {}, "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw=="], + "@tsconfig/node10": ["@tsconfig/node10@1.0.12", "", {}, "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ=="], "@tsconfig/node12": ["@tsconfig/node12@1.0.11", "", {}, "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="], @@ -1162,7 +1160,7 @@ "@types/content-disposition": ["@types/content-disposition@0.5.9", "", {}, "sha512-8uYXI3Gw35MhiVYhG3s295oihrxRyytcRHjSjqnqZVDDy/xcGBRny7+Xj1Wgfhv5QzRtN2hB2dVRBUX9XW3UcQ=="], - "@types/cookies": ["@types/cookies@0.9.1", "", { "dependencies": { "@types/connect": "*", "@types/express": "*", "@types/keygrip": "*", "@types/node": "*" } }, "sha512-E/DPgzifH4sM1UMadJMWd6mO2jOd4g1Ejwzx8/uRCDpJis1IrlyQEcGAYEomtAqRYmD5ORbNXMeI9U0RiVGZbg=="], + "@types/cookies": ["@types/cookies@0.9.2", "", { "dependencies": { "@types/connect": "*", "@types/express": "*", "@types/keygrip": "*", "@types/node": "*" } }, "sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A=="], "@types/cors": ["@types/cors@2.8.19", "", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="], @@ -1176,7 +1174,7 @@ "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "@types/express": ["@types/express@4.17.23", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ=="], + "@types/express": ["@types/express@4.17.25", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "^1" } }, "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw=="], "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.7", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg=="], @@ -1214,13 +1212,13 @@ "@types/keygrip": ["@types/keygrip@1.0.6", "", {}, "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ=="], - "@types/koa": ["@types/koa@3.0.0", "", { "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", "@types/cookies": "*", "@types/http-assert": "*", "@types/http-errors": "^2", "@types/keygrip": "*", "@types/koa-compose": "*", "@types/node": "*" } }, "sha512-MOcVYdVYmkSutVHZZPh8j3+dAjLyR5Tl59CN0eKgpkE1h/LBSmPAsQQuWs+bKu7WtGNn+hKfJH9Gzml+PulmDg=="], + "@types/koa": ["@types/koa@3.0.1", "", { "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", "@types/cookies": "*", "@types/http-assert": "*", "@types/http-errors": "^2", "@types/keygrip": "*", "@types/koa-compose": "*", "@types/node": "*" } }, "sha512-VkB6WJUQSe0zBpR+Q7/YIUESGp5wPHcaXr0xueU5W0EOUWtlSbblsl+Kl31lyRQ63nIILh0e/7gXjQ09JXJIHw=="], - "@types/koa-compose": ["@types/koa-compose@3.2.8", "", { "dependencies": { "@types/koa": "*" } }, "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA=="], + "@types/koa-compose": ["@types/koa-compose@3.2.9", "", { "dependencies": { "@types/koa": "*" } }, "sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA=="], "@types/leaflet": ["@types/leaflet@1.9.21", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w=="], - "@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="], + "@types/lodash": ["@types/lodash@4.17.21", "", {}, "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="], "@types/lodash.clonedeep": ["@types/lodash.clonedeep@4.5.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q=="], @@ -1246,9 +1244,9 @@ "@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="], - "@types/send": ["@types/send@1.2.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ=="], + "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], - "@types/serve-static": ["@types/serve-static@1.15.9", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA=="], + "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], "@types/sodium-native": ["@types/sodium-native@2.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-jZIg5ltGH1okmnH3FrLQsgwjcjOVozMSHwSiEm1/LpMekhOMHbQqp21P4H24mizh1BjwI6Q8qmphmD/HJuAqWg=="], @@ -1260,25 +1258,25 @@ "@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], - "@types/yargs": ["@types/yargs@16.0.9", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA=="], + "@types/yargs": ["@types/yargs@16.0.11", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], "@types/zen-observable": ["@types/zen-observable@0.8.7", "", {}, "sha512-LKzNTjj+2j09wAo/vvVjzgw5qckJJzhdGgWHW7j69QIGdq/KnZrMAMIHQiWGl3Ccflh5/CudBAntTPYdprPltA=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.1", "@typescript-eslint/types": "^8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.48.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.48.0", "@typescript-eslint/types": "^8.48.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1" } }, "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.48.0", "", { "dependencies": { "@typescript-eslint/types": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0" } }, "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.48.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.48.0", "", {}, "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.1", "@typescript-eslint/tsconfig-utils": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.48.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.48.0", "@typescript-eslint/tsconfig-utils": "8.48.0", "@typescript-eslint/types": "8.48.0", "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@7.18.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.48.0", "", { "dependencies": { "@typescript-eslint/types": "8.48.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], @@ -1314,19 +1312,19 @@ "@vue/compat": ["@vue/compat@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-Q3xRdTPN4l+kddxU98REyUBgvc0meAo9CefCWE2lW8Fg3dyPn3vSCce52b338ihrJAx1RQQhO5wMWhJ/PAKUpA=="], - "@vue/compiler-core": ["@vue/compiler-core@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/shared": "3.5.22", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.25", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.25", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw=="], - "@vue/compiler-dom": ["@vue/compiler-dom@3.5.22", "", { "dependencies": { "@vue/compiler-core": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA=="], + "@vue/compiler-dom": ["@vue/compiler-dom@3.5.25", "", { "dependencies": { "@vue/compiler-core": "3.5.25", "@vue/shared": "3.5.25" } }, "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q=="], - "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/compiler-core": "3.5.22", "@vue/compiler-dom": "3.5.22", "@vue/compiler-ssr": "3.5.22", "@vue/shared": "3.5.22", "estree-walker": "^2.0.2", "magic-string": "^0.30.19", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ=="], + "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.25", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/compiler-core": "3.5.25", "@vue/compiler-dom": "3.5.25", "@vue/compiler-ssr": "3.5.25", "@vue/shared": "3.5.25", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag=="], - "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.22", "", { "dependencies": { "@vue/compiler-dom": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww=="], + "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.25", "", { "dependencies": { "@vue/compiler-dom": "3.5.25", "@vue/shared": "3.5.25" } }, "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A=="], "@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="], - "@vue/devtools-kit": ["@vue/devtools-kit@7.7.7", "", { "dependencies": { "@vue/devtools-shared": "^7.7.7", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA=="], + "@vue/devtools-kit": ["@vue/devtools-kit@7.7.9", "", { "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA=="], - "@vue/devtools-shared": ["@vue/devtools-shared@7.7.7", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw=="], + "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="], "@vue/eslint-config-prettier": ["@vue/eslint-config-prettier@10.2.0", "", { "dependencies": { "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2" }, "peerDependencies": { "eslint": ">= 8.21.0", "prettier": ">= 3.0.0" } }, "sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw=="], @@ -1338,7 +1336,7 @@ "@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], - "@vue/shared": ["@vue/shared@3.5.22", "", {}, "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w=="], + "@vue/shared": ["@vue/shared@3.5.25", "", {}, "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg=="], "@vue/test-utils": ["@vue/test-utils@2.4.6", "", { "dependencies": { "js-beautify": "^1.14.9", "vue-component-type-helpers": "^2.0.0" } }, "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow=="], @@ -1544,7 +1542,7 @@ "auto-changelog": ["auto-changelog@2.5.0", "", { "dependencies": { "commander": "^7.2.0", "handlebars": "^4.7.7", "import-cwd": "^3.0.0", "node-fetch": "^2.6.1", "parse-github-url": "^1.0.3", "semver": "^7.3.5" }, "bin": { "auto-changelog": "src/index.js" } }, "sha512-UTnLjT7I9U2U/xkCUH5buDlp8C7g0SGChfib+iDrJkamcj5kaMqNKHNfbKJw1kthJUq8sUo3i3q2S6FzO/l/wA=="], - "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="], + "autoprefixer": ["autoprefixer@10.4.22", "", { "dependencies": { "browserslist": "^4.27.0", "caniuse-lite": "^1.0.30001754", "fraction.js": "^5.3.4", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg=="], "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], @@ -1574,23 +1572,17 @@ "balanced-match": ["balanced-match@2.0.0", "", {}, "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA=="], - "bare-addon-resolve": ["bare-addon-resolve@1.9.5", "", { "dependencies": { "bare-module-resolve": "^1.10.0", "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-XdqrG73zLK9LDfblOJwoAxmJ+7YdfRW4ex46+f4L+wPhk7H7LDrRMAbBw8s8jkxeEFpUenyB7QHnv0ErAWd3Yg=="], + "bare-addon-resolve": ["bare-addon-resolve@1.9.6", "", { "dependencies": { "bare-module-resolve": "^1.10.0", "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-hvOQY1zDK6u0rSr27T6QlULoVLwi8J2k8HHHJlxSfT7XQdQ/7bsS+AnjYkHtu/TkL+gm3aMXAKucJkJAbrDG/g=="], - "bare-events": ["bare-events@2.8.0", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA=="], + "bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="], - "bare-module-resolve": ["bare-module-resolve@1.11.2", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-HIBu9WacMejg3Dz4X1v6lJjp7ECnwpujvuLub+8I7JJLRwJaGxWMzGYvieOoS9R1n5iRByvTmLtIdPbwjfRgiQ=="], + "bare-module-resolve": ["bare-module-resolve@1.12.0", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-JrzrqlC3Tds0iKRwQs8xIIJ+FRieKA9ll0jaqpotDLZtjJPVevzRoeuUYZ5GIo1t1z7/pIRdk85Q3i/2xQLfEQ=="], - "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="], - - "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], - - "bare-semver": ["bare-semver@1.0.1", "", {}, "sha512-UtggzHLiTrmFOC/ogQ+Hy7VfoKoIwrP1UFcYtTxoCUdLtsIErT8+SWtOC2DH/snT9h+xDrcBEPcwKei1mzemgg=="], - - "bare-url": ["bare-url@2.3.1", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-v2yl0TnaZTdEnelkKtXZGnotiV6qATBlnNuUMrHl6v9Lmmrh9mw9RYyImPU7/4RahumSwQS1k2oKXcRfXcbjJw=="], + "bare-semver": ["bare-semver@1.0.2", "", {}, "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.8.18", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.31", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw=="], "bignumber.js": ["bignumber.js@9.0.0", "", {}, "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="], @@ -1600,7 +1592,7 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - "birpc": ["birpc@2.6.1", "", {}, "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ=="], + "birpc": ["birpc@2.8.0", "", {}, "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw=="], "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], @@ -1616,7 +1608,7 @@ "bootstrap-vue-next": ["bootstrap-vue-next@0.26.8", "", { "peerDependencies": { "vue": "^3.5.13" } }, "sha512-2WolMPi4XB0J/736PPglDCIjUz2pwvOhu3SLjQYP0Rh5IncspMZMkUCa/H28Vh45xQadFtrYeBPyPF3JrpbadA=="], - "bowser": ["bowser@2.12.1", "", {}, "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw=="], + "bowser": ["bowser@2.13.0", "", {}, "sha512-yHAbSRuT6LTeKi6k2aS40csueHqgAsFEgmrOsfRyFpJnFv5O2hl9FYmWEUZ97gZ/dG17U4IQQcTx4YAFYPuWRQ=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], @@ -1624,7 +1616,7 @@ "browser-process-hrtime": ["browser-process-hrtime@1.0.0", "", {}, "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="], - "browserslist": ["browserslist@4.26.3", "", { "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w=="], + "browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="], "bs-logger": ["bs-logger@0.2.6", "", { "dependencies": { "fast-json-stable-stringify": "2.x" } }, "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog=="], @@ -1646,11 +1638,11 @@ "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - "c12": ["c12@3.3.1", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-LcWQ01LT9tkoUINHgpIOv3mMs+Abv7oVCrtpMRi1PaapVEpWoMga5WuT7/DqFTu7URP9ftbOmimNw1KNIGh9DQ=="], + "c12": ["c12@3.3.2", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A=="], "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "cacheable": ["cacheable@2.1.1", "", { "dependencies": { "@cacheable/memoize": "^2.0.3", "@cacheable/memory": "^2.0.3", "@cacheable/utils": "^2.1.0", "hookified": "^1.12.2", "keyv": "^5.5.3", "qified": "^0.5.0" } }, "sha512-LmF4AXiSNdiRbI2UjH8pAp9NIXxeQsTotpEaegPiDcnN0YPygDJDV3l/Urc0mL72JWdATEorKqIHEx55nDlONg=="], + "cacheable": ["cacheable@2.2.0", "", { "dependencies": { "@cacheable/memory": "^2.0.5", "@cacheable/utils": "^2.3.0", "hookified": "^1.13.0", "keyv": "^5.5.4", "qified": "^0.5.2" } }, "sha512-LEJxRqfeomiiRd2t0uON6hxAtgOoWDfY3fugebbz+J3vDLO+SkdfFChQcOHTZhj9SYa9iwE9MGYNX72dKiOE4w=="], "cacheable-lookup": ["cacheable-lookup@7.0.0", "", {}, "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="], @@ -1668,7 +1660,7 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001757", "", {}, "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ=="], "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], @@ -1704,8 +1696,6 @@ "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], - "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], - "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], "collect-v8-coverage": ["collect-v8-coverage@1.0.3", "", {}, "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw=="], @@ -1748,17 +1738,17 @@ "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], "cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], - "copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="], + "copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="], "core": ["core@workspace:core"], - "core-js-pure": ["core-js-pure@3.46.0", "", {}, "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw=="], + "core-js-pure": ["core-js-pure@3.47.0", "", {}, "sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw=="], "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], @@ -1794,7 +1784,7 @@ "cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="], - "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="], @@ -1810,7 +1800,7 @@ "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], - "dayjs": ["dayjs@1.11.18", "", {}, "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="], + "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -1910,7 +1900,7 @@ "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "electron-to-chromium": ["electron-to-chromium@1.5.237", "", {}, "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg=="], + "electron-to-chromium": ["electron-to-chromium@1.5.260", "", {}, "sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA=="], "email-templates": ["email-templates@10.0.1", "", { "dependencies": { "@ladjs/i18n": "^8.0.1", "consolidate": "^0.16.0", "get-paths": "^0.0.7", "html-to-text": "^8.2.0", "juice": "^8.0.0", "lodash": "^4.17.21", "nodemailer": "^6.7.7", "preview-email": "^3.0.7" } }, "sha512-LNZKS0WW9XQkjuDZd/4p/1Q/pwqaqXOP3iDxTIVIQY9vuHlIUEcRLFo8/Xh3GtZCBnm181VgvOXIABKTVyTePA=="], @@ -1952,7 +1942,7 @@ "es6-promise": ["es6-promise@4.2.8", "", {}, "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="], - "esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -2042,7 +2032,7 @@ "express-slow-down": ["express-slow-down@2.1.0", "", { "dependencies": { "express-rate-limit": "7" }, "peerDependencies": { "express": "4 || 5 || ^5.0.0-beta.1" } }, "sha512-tQ/ItTDbGfo+fLS+jxu19vgYOgZk7wyOakuAsnzl8f7HmxG3ynWAoo136+oqB+rqHCk3QyM6VoXL03qA5a4gVQ=="], - "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], "ext-list": ["ext-list@2.2.2", "", { "dependencies": { "mime-db": "^1.28.0" } }, "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA=="], @@ -2060,7 +2050,7 @@ "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], - "fast-equals": ["fast-equals@5.3.2", "", {}, "sha512-6rxyATwPCkaFIL3JLqw8qXqMpIZ942pTX/tbQFkRsDGblS8tNGtlUauA/+mt6RUfqn/4MoEr+WDkYoIQbibWuQ=="], + "fast-equals": ["fast-equals@5.3.3", "", {}, "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw=="], "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], @@ -2122,7 +2112,7 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], @@ -2130,7 +2120,7 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], @@ -2174,7 +2164,7 @@ "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "get-tsconfig": ["get-tsconfig@4.12.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw=="], + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], @@ -2240,6 +2230,8 @@ "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + "hashery": ["hashery@1.2.0", "", { "dependencies": { "hookified": "^1.13.0" } }, "sha512-43XJKpwle72Ik5Zpam7MuzRWyNdwwdf6XHlh8wCj2PggvWf+v/Dm5B0dxGZOmddidgeO6Ofu9As/o231Ti/9PA=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], @@ -2250,7 +2242,7 @@ "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], - "hookified": ["hookified@1.12.2", "", {}, "sha512-aokUX1VdTpI0DUsndvW+OiwmBpKCu/NgRsSSkuSY0zq8PY6Q6a+lmOfAFDXAAOtBqJELvcWY9L1EVtzjbQcMdg=="], + "hookified": ["hookified@1.13.0", "", {}, "sha512-6sPYUY8olshgM/1LDNW4QZQN0IqgKhtl/1C8koNZBJrKLBk3AZl6chQtNwpNztvfiApHMEwMHek5rv993PRbWw=="], "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], @@ -2280,7 +2272,7 @@ "hypercore-crypto": ["hypercore-crypto@3.6.1", "", { "dependencies": { "b4a": "^1.6.6", "compact-encoding": "^2.15.0", "sodium-universal": "^5.0.0" } }, "sha512-ltIz2uDwy9pO/ZGTvqcjzyBkvt6O4cVm4r/nNxh0GFs/RbQtqP/i4wCvLEdmU7ptgtnw7fI67WYD1aHPuv4OVA=="], - "i18n": ["i18n@0.15.2", "", { "dependencies": { "@messageformat/core": "^3.4.0", "debug": "^4.4.3", "fast-printf": "^1.6.10", "make-plural": "^7.4.0", "math-interval-parser": "^2.0.1", "mustache": "^4.2.0" } }, "sha512-mdBxCfC651UL/hNizIQgB1NHwbBKjlrPcsoTzd/X8rNbJlS1FMF//TOyHEVFg9Dxo0RcrI2ZKt1AFTNe3Q40og=="], + "i18n": ["i18n@0.15.3", "", { "dependencies": { "@messageformat/core": "^3.4.0", "debug": "^4.4.3", "fast-printf": "^1.6.10", "make-plural": "^7.4.0", "math-interval-parser": "^2.0.1", "mustache": "^4.2.0" } }, "sha512-tW/AA5R4lJZLnd60Agcd0PfXB1C2G7UqTrdNewuv/SIYdxcHkCE8w4Zx1SgCjJ+2BLuAAGIG/KXb/xNYF1lO5Q=="], "i18n-locales": ["i18n-locales@0.0.5", "", { "dependencies": { "@ladjs/country-language": "^0.2.1" } }, "sha512-Kve1AHy6rqyfJHPy8MIvaKBKhHhHPXV+a/TgMkjp3UBhO3gfWR40ZQn8Xy7LI6g3FhmbvkFtv+GCZy6yvuyeHQ=="], @@ -2316,7 +2308,7 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "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" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], + "ioredis": ["ioredis@5.8.2", "", { "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.2", "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" } }, "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -2402,7 +2394,7 @@ "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], + "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], @@ -2500,7 +2492,7 @@ "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "jsdom": ["jsdom@25.0.1", "", { "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.12", "parse5": "^7.1.2", "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^2.11.2" }, "optionalPeers": ["canvas"] }, "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw=="], @@ -2540,7 +2532,7 @@ "klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="], - "knitwork": ["knitwork@1.2.0", "", {}, "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg=="], + "knitwork": ["knitwork@1.3.0", "", {}, "sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw=="], "known-css-properties": ["known-css-properties@0.37.0", "", {}, "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ=="], @@ -2560,7 +2552,7 @@ "libmime": ["libmime@5.3.7", "", { "dependencies": { "encoding-japanese": "2.2.0", "iconv-lite": "0.6.3", "libbase64": "1.3.0", "libqp": "2.1.1" } }, "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw=="], - "libphonenumber-js": ["libphonenumber-js@1.12.24", "", {}, "sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ=="], + "libphonenumber-js": ["libphonenumber-js@1.12.29", "", {}, "sha512-P2aLrbeqHbmh8+9P35LXQfXOKc7XJ0ymUKl7tyeyQjdRNfzunXWxQXGc4yl3fUf28fqLRfPY+vIVvFXK7KEBTw=="], "libqp": ["libqp@2.1.1", "", {}, "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow=="], @@ -2634,7 +2626,7 @@ "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], - "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], @@ -2682,7 +2674,7 @@ "mimic-response": ["mimic-response@4.0.0", "", {}, "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="], - "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -2746,7 +2738,7 @@ "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], - "node-releases": ["node-releases@2.0.25", "", {}, "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="], @@ -2960,7 +2952,7 @@ "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - "qified": ["qified@0.5.1", "", { "dependencies": { "hookified": "^1.12.2" } }, "sha512-+BtFN3dCP+IaFA6IYNOu/f/uK1B8xD2QWyOeCse0rjtAebBmkzgd2d1OAXi3ikAzJMIBSdzZDNZ3wZKEUDQs5w=="], + "qified": ["qified@0.5.2", "", { "dependencies": { "hookified": "^1.13.0" } }, "sha512-7gJ6mxcQb9vUBOtbKm5mDevbe2uRcOEVp1g4gb/Q+oLntB3HY8eBhOYRxFI2mlDFlY1e4DOSCptzxarXRvzxCA=="], "qrcanvas": ["qrcanvas@3.1.2", "", { "dependencies": { "@babel/runtime": "^7.11.2", "qrcode-generator": "^1.4.4" } }, "sha512-lNcAyCHN0Eno/mJ5eBc7lHV/5ejAJxII0UELthG3bNnlLR+u8hCc7CR+hXBawbYUf96kNIosXfG2cJzx92ZWKg=="], @@ -3022,7 +3014,7 @@ "relateurl": ["relateurl@0.2.7", "", {}, "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog=="], - "require-addon": ["require-addon@1.1.0", "", { "dependencies": { "bare-addon-resolve": "^1.3.0", "bare-url": "^2.1.0" } }, "sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg=="], + "require-addon": ["require-addon@1.2.0", "", { "dependencies": { "bare-addon-resolve": "^1.3.0" } }, "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA=="], "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], @@ -3030,7 +3022,7 @@ "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], @@ -3054,7 +3046,7 @@ "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "rollup": ["rollup@4.52.5", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.5", "@rollup/rollup-android-arm64": "4.52.5", "@rollup/rollup-darwin-arm64": "4.52.5", "@rollup/rollup-darwin-x64": "4.52.5", "@rollup/rollup-freebsd-arm64": "4.52.5", "@rollup/rollup-freebsd-x64": "4.52.5", "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", "@rollup/rollup-linux-arm-musleabihf": "4.52.5", "@rollup/rollup-linux-arm64-gnu": "4.52.5", "@rollup/rollup-linux-arm64-musl": "4.52.5", "@rollup/rollup-linux-loong64-gnu": "4.52.5", "@rollup/rollup-linux-ppc64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-musl": "4.52.5", "@rollup/rollup-linux-s390x-gnu": "4.52.5", "@rollup/rollup-linux-x64-gnu": "4.52.5", "@rollup/rollup-linux-x64-musl": "4.52.5", "@rollup/rollup-openharmony-arm64": "4.52.5", "@rollup/rollup-win32-arm64-msvc": "4.52.5", "@rollup/rollup-win32-ia32-msvc": "4.52.5", "@rollup/rollup-win32-x64-gnu": "4.52.5", "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw=="], + "rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="], "rrweb-cssom": ["rrweb-cssom@0.7.1", "", {}, "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg=="], @@ -3078,7 +3070,7 @@ "safety-catch": ["safety-catch@1.0.2", "", {}, "sha512-C1UYVZ4dtbBxEtvOcpjBaaD27nP8MlvyAQEp2fOTOEe6pfUpk1cDUxij6BR1jZup6rSyUTaBBplK7LanskrULA=="], - "sass": ["sass@1.93.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg=="], + "sass": ["sass@1.94.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A=="], "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], @@ -3216,13 +3208,11 @@ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], - "stylelint": ["stylelint@16.25.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3", "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.2.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", "css-tree": "^3.1.0", "debug": "^4.4.3", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^10.1.4", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", "ignore": "^7.0.5", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.37.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.5.6", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "supports-hyperlinks": "^3.2.0", "svg-tags": "^1.0.0", "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" } }, "sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ=="], + "stylelint": ["stylelint@16.26.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@csstools/media-query-list-parser": "^4.0.3", "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.2.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", "css-tree": "^3.1.0", "debug": "^4.4.3", "fast-glob": "^3.3.3", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^11.1.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", "ignore": "^7.0.5", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.37.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.5.6", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^7.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", "supports-hyperlinks": "^3.2.0", "svg-tags": "^1.0.0", "table": "^6.9.0", "write-file-atomic": "^5.0.1" }, "bin": { "stylelint": "bin/stylelint.mjs" } }, "sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ=="], "stylelint-config-html": ["stylelint-config-html@1.1.0", "", { "peerDependencies": { "postcss-html": "^1.0.0", "stylelint": ">=14.0.0" } }, "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ=="], @@ -3240,7 +3230,7 @@ "subscriptions-transport-ws": ["subscriptions-transport-ws@0.9.19", "", { "dependencies": { "backo2": "^1.0.2", "eventemitter3": "^3.1.0", "iterall": "^1.2.1", "symbol-observable": "^1.0.4", "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" }, "peerDependencies": { "graphql": ">=0.10.0" } }, "sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw=="], - "superjson": ["superjson@2.2.2", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q=="], + "superjson": ["superjson@2.2.5", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w=="], "supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], @@ -3264,7 +3254,7 @@ "terminal-link": ["terminal-link@2.1.1", "", { "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" } }, "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ=="], - "terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="], + "terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="], "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], @@ -3290,7 +3280,7 @@ "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -3348,23 +3338,23 @@ "tsx": ["tsx@4.20.6", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg=="], - "tua-body-scroll-lock": ["tua-body-scroll-lock@1.5.3", "", {}, "sha512-44W12iqek41kZuTdpEUt3JTUsMx0IxfTajXWfQyMLgzsPaMYUPZLcJkwa4P0x24h5DQ3lYvDuYvphBo4+L0t4w=="], + "tua-body-scroll-lock": ["tua-body-scroll-lock@1.6.1", "", {}, "sha512-BKJ8Jg8/SoSeE2GgKXeLKYZesa5cIGUj3jupGtnM3HoZIa5dsa+p6aeHhN6rHlP1KW7bNDsc1fhKkf4fm0krug=="], "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], - "turbo": ["turbo@2.5.8", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.8", "turbo-darwin-arm64": "2.5.8", "turbo-linux-64": "2.5.8", "turbo-linux-arm64": "2.5.8", "turbo-windows-64": "2.5.8", "turbo-windows-arm64": "2.5.8" }, "bin": { "turbo": "bin/turbo" } }, "sha512-5c9Fdsr9qfpT3hA0EyYSFRZj1dVVsb6KIWubA9JBYZ/9ZEAijgUEae0BBR/Xl/wekt4w65/lYLTFaP3JmwSO8w=="], + "turbo": ["turbo@2.6.1", "", { "optionalDependencies": { "turbo-darwin-64": "2.6.1", "turbo-darwin-arm64": "2.6.1", "turbo-linux-64": "2.6.1", "turbo-linux-arm64": "2.6.1", "turbo-windows-64": "2.6.1", "turbo-windows-arm64": "2.6.1" }, "bin": { "turbo": "bin/turbo" } }, "sha512-qBwXXuDT3rA53kbNafGbT5r++BrhRgx3sAo0cHoDAeG9g1ItTmUMgltz3Hy7Hazy1ODqNpR+C7QwqL6DYB52yA=="], - "turbo-darwin-64": ["turbo-darwin-64@2.5.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ=="], + "turbo-darwin-64": ["turbo-darwin-64@2.6.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dm0HwhyZF4J0uLqkhUyCVJvKM9Rw7M03v3J9A7drHDQW0qAbIGBrUijQ8g4Q9Cciw/BXRRd8Uzkc3oue+qn+ZQ=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f1H/tQC9px7+hmXn6Kx/w8Jd/FneIUnvLlcI/7RGHunxfOkKJKvsoiNzySkoHQ8uq1pJnhJ0xNGTlYM48ZaJOQ=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.6.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-U0PIPTPyxdLsrC3jN7jaJUwgzX5sVUBsKLO7+6AL+OASaa1NbT1pPdiZoTkblBAALLP76FM0LlnsVQOnmjYhyw=="], - "turbo-linux-64": ["turbo-linux-64@2.5.8", "", { "os": "linux", "cpu": "x64" }, "sha512-hMyvc7w7yadBlZBGl/bnR6O+dJTx3XkTeyTTH4zEjERO6ChEs0SrN8jTFj1lueNXKIHh1SnALmy6VctKMGnWfw=="], + "turbo-linux-64": ["turbo-linux-64@2.6.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eM1uLWgzv89bxlK29qwQEr9xYWBhmO/EGiH22UGfq+uXr+QW1OvNKKMogSN65Ry8lElMH4LZh0aX2DEc7eC0Mw=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.5.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-LQELGa7bAqV2f+3rTMRPnj5G/OHAe2U+0N9BwsZvfMvHSUbsQ3bBMWdSQaYNicok7wOZcHjz2TkESn1hYK6xIQ=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.6.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MFFh7AxAQAycXKuZDrbeutfWM5Ep0CEZ9u7zs4Hn2FvOViTCzIfEhmuJou3/a5+q5VX1zTxQrKGy+4Lf5cdpsA=="], - "turbo-windows-64": ["turbo-windows-64@2.5.8", "", { "os": "win32", "cpu": "x64" }, "sha512-3YdcaW34TrN1AWwqgYL9gUqmZsMT4T7g8Y5Azz+uwwEJW+4sgcJkIi9pYFyU4ZBSjBvkfuPZkGgfStir5BBDJQ=="], + "turbo-windows-64": ["turbo-windows-64@2.6.1", "", { "os": "win32", "cpu": "x64" }, "sha512-buq7/VAN7KOjMYi4tSZT5m+jpqyhbRU2EUTTvp6V0Ii8dAkY2tAAjQN1q5q2ByflYWKecbQNTqxmVploE0LVwQ=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.5.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-eFC5XzLmgXJfnAK3UMTmVECCwuBcORrWdewoiXBnUm934DY6QN8YowC/srhNnROMpaKaqNeRpoB5FxCww3eteQ=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.6.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-7w+AD5vJp3R+FB0YOj1YJcNcOOvBior7bcHTodqp90S3x3bLgpr7tE6xOea1e8JkP7GK6ciKVUpQvV7psiwU5Q=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], @@ -3418,8 +3408,6 @@ "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], - "unimport": ["unimport@5.5.0", "", { "dependencies": { "acorn": "^8.15.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.19", "mlly": "^1.8.0", "pathe": "^2.0.3", "picomatch": "^4.0.3", "pkg-types": "^2.3.0", "scule": "^1.3.0", "strip-literal": "^3.1.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.10", "unplugin-utils": "^0.3.0" } }, "sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg=="], - "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], @@ -3428,15 +3416,13 @@ "unplugin-icons": ["unplugin-icons@0.19.3", "", { "dependencies": { "@antfu/install-pkg": "^0.4.1", "@antfu/utils": "^0.7.10", "@iconify/utils": "^2.1.29", "debug": "^4.3.6", "kolorist": "^1.8.0", "local-pkg": "^0.5.0", "unplugin": "^1.12.0" }, "peerDependencies": { "@svgr/core": ">=7.0.0", "@svgx/core": "^1.0.1", "@vue/compiler-sfc": "^3.0.2 || ^2.7.0", "vue-template-compiler": "^2.6.12", "vue-template-es2015-compiler": "^1.9.0" }, "optionalPeers": ["@svgr/core", "@svgx/core", "@vue/compiler-sfc", "vue-template-compiler", "vue-template-es2015-compiler"] }, "sha512-EUegRmsAI6+rrYr0vXjFlIP+lg4fSC4zb62zAZKx8FGXlWAGgEGBCa3JDe27aRAXhistObLPbBPhwa/0jYLFkQ=="], - "unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="], - "unplugin-vue-components": ["unplugin-vue-components@0.27.5", "", { "dependencies": { "@antfu/utils": "^0.7.10", "@rollup/pluginutils": "^5.1.3", "chokidar": "^3.6.0", "debug": "^4.3.7", "fast-glob": "^3.3.2", "local-pkg": "^0.5.1", "magic-string": "^0.30.14", "minimatch": "^9.0.5", "mlly": "^1.7.3", "unplugin": "^1.16.0" }, "peerDependencies": { "@babel/parser": "^7.15.8", "@nuxt/kit": "^3.2.2", "vue": "2 || 3" }, "optionalPeers": ["@babel/parser", "@nuxt/kit"] }, "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg=="], "unslab": ["unslab@1.3.0", "", { "dependencies": { "b4a": "^1.6.6" } }, "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ=="], "untyped": ["untyped@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "defu": "^6.1.4", "jiti": "^2.4.2", "knitwork": "^1.2.0", "scule": "^1.3.0" }, "bin": { "untyped": "dist/cli.mjs" } }, "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g=="], - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -3456,7 +3442,7 @@ "valid-data-url": ["valid-data-url@3.0.1", "", {}, "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA=="], - "validator": ["validator@13.15.15", "", {}, "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A=="], + "validator": ["validator@13.15.23", "", {}, "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], @@ -3520,7 +3506,7 @@ "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], - "webpack": ["webpack@5.102.1", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.26.3", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.4", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ=="], + "webpack": ["webpack@5.103.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.26.3", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.4", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw=="], "webpack-sources": ["webpack-sources@3.3.3", "", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="], @@ -3622,15 +3608,17 @@ "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@cacheable/memory/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "@cacheable/memory/keyv": ["keyv@5.5.4", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ=="], - "@cacheable/utils/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "@cacheable/utils/keyv": ["keyv@5.5.4", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], @@ -3656,13 +3644,17 @@ "@iconify/utils/local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], - "@intlify/bundle-utils/@intlify/message-compiler": ["@intlify/message-compiler@11.1.12", "", { "dependencies": { "@intlify/shared": "11.1.12", "source-map-js": "^1.0.2" } }, "sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ=="], + "@intlify/bundle-utils/@intlify/message-compiler": ["@intlify/message-compiler@11.2.2", "", { "dependencies": { "@intlify/shared": "11.2.2", "source-map-js": "^1.0.2" } }, "sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA=="], - "@intlify/bundle-utils/@intlify/shared": ["@intlify/shared@11.1.12", "", {}, "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A=="], + "@intlify/bundle-utils/@intlify/shared": ["@intlify/shared@11.2.2", "", {}, "sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw=="], - "@intlify/bundle-utils/yaml-eslint-parser": ["yaml-eslint-parser@1.3.0", "", { "dependencies": { "eslint-visitor-keys": "^3.0.0", "yaml": "^2.0.0" } }, "sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA=="], + "@intlify/bundle-utils/yaml-eslint-parser": ["yaml-eslint-parser@1.3.1", "", { "dependencies": { "eslint-visitor-keys": "^3.0.0", "yaml": "^2.0.0" } }, "sha512-MdSgP9YA9QjtAO2+lt4O7V2bnH22LPnfeVLiQqjY3cOyn8dy/Ief8otjIe6SPPTK03nM7O3Yl0LTfWuF7l+9yw=="], - "@intlify/unplugin-vue-i18n/@intlify/shared": ["@intlify/shared@11.1.12", "", {}, "sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A=="], + "@intlify/core-base/@intlify/shared": ["@intlify/shared@9.14.5", "", {}, "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ=="], + + "@intlify/message-compiler/@intlify/shared": ["@intlify/shared@9.14.5", "", {}, "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ=="], + + "@intlify/unplugin-vue-i18n/@intlify/shared": ["@intlify/shared@11.2.2", "", {}, "sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw=="], "@intlify/vue-i18n-extensions/@intlify/shared": ["@intlify/shared@10.0.8", "", {}, "sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw=="], @@ -3678,7 +3670,7 @@ "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], - "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], "@jest/console/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], @@ -3704,15 +3696,13 @@ "@jest/source-map/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "@jest/transform/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], - "@jest/transform/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "@jest/transform/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], "@jest/types/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], - "@keyv/bigmap/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "@keyv/bigmap/keyv": ["keyv@5.5.4", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ=="], "@morev/utils/ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], @@ -3764,7 +3754,7 @@ "@types/serve-static/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], - "@types/serve-static/@types/send": ["@types/send@0.17.5", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w=="], + "@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], "@types/sodium-native/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], @@ -3870,7 +3860,7 @@ "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "cacheable/keyv": ["keyv@5.5.3", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A=="], + "cacheable/keyv": ["keyv@5.5.4", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -4044,7 +4034,7 @@ "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "js-beautify/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "jsdom/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], @@ -4144,7 +4134,7 @@ "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "stylelint/file-entry-cache": ["file-entry-cache@10.1.4", "", { "dependencies": { "flat-cache": "^6.1.13" } }, "sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA=="], + "stylelint/file-entry-cache": ["file-entry-cache@11.1.1", "", { "dependencies": { "flat-cache": "^6.1.19" } }, "sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A=="], "stylelint/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], @@ -4158,7 +4148,7 @@ "stylelint-scss/known-css-properties": ["known-css-properties@0.36.0", "", {}, "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA=="], - "stylelint-scss/mdn-data": ["mdn-data@2.24.0", "", {}, "sha512-i97fklrJl03tL1tdRVw0ZfLLvuDsdb6wxL+TrJ+PKkCbLrp2PCu2+OYdCKychIUm19nSM/35S6qz7pJpnXttoA=="], + "stylelint-scss/mdn-data": ["mdn-data@2.25.0", "", {}, "sha512-T2LPsjgUE/tgMmRXREVmwsux89DwWfNjiynOeXuLd2mX6jphGQ2YE3Ukz7LQ2VOFKiVZU/Ee1GqzHiipZCjymw=="], "stylelint-scss/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], @@ -4180,7 +4170,7 @@ "terser-webpack-plugin/serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - "test-exclude/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "test-exclude/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -4196,7 +4186,7 @@ "typeorm/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "typeorm/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "typeorm/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "typeorm/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], @@ -4204,33 +4194,19 @@ "unctx/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - "unctx/unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], - - "unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], - - "unimport/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - - "unimport/local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], - - "unimport/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - - "unimport/unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="], - - "unplugin-utils/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "unctx/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], "unplugin-vue-components/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "unplugin-vue-components/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "v8-to-istanbul/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], - - "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="], + "vee-validate/@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="], "vee-validate/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - "vite-plugin-graphql-loader/graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], + "vite-plugin-graphql-loader/graphql": ["graphql@16.12.0", "", {}, "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ=="], "vite-plugin-html/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], @@ -4250,6 +4226,8 @@ "vue-apollo/throttle-debounce": ["throttle-debounce@2.3.0", "", {}, "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="], + "vue-i18n/@intlify/core-base": ["@intlify/core-base@9.13.1", "", { "dependencies": { "@intlify/message-compiler": "9.13.1", "@intlify/shared": "9.13.1" } }, "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w=="], + "web-resource-inliner/htmlparser2": ["htmlparser2@5.0.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", "domutils": "^2.4.2", "entities": "^2.0.0" } }, "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ=="], "web-resource-inliner/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], @@ -4276,7 +4254,7 @@ "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "@hyperswarm/secret-stream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "@hyperswarm/secret-stream/sodium-universal/sodium-native": ["sodium-native@5.0.10", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-UIw+0AbpCQRuTJF88JWrZomP4O+PXhlWvdopiAJOsUivTyHTf3korMyStxkZuPngSbBEtEfDdc4ewEd8/T4/lA=="], "@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base": ["@intlify/core-base@10.0.8", "", { "dependencies": { "@intlify/message-compiler": "10.0.8", "@intlify/shared": "10.0.8" } }, "sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ=="], @@ -4292,7 +4270,7 @@ "@jest/create-cache-key-function/@jest/types/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], - "@jest/create-cache-key-function/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@jest/create-cache-key-function/@jest/types/@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], "@jest/reporters/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -4336,7 +4314,7 @@ "dht-node/ts-jest/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - "dht-rpc/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "dht-rpc/sodium-universal/sodium-native": ["sodium-native@5.0.10", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-UIw+0AbpCQRuTJF88JWrZomP4O+PXhlWvdopiAJOsUivTyHTf3korMyStxkZuPngSbBEtEfDdc4ewEd8/T4/lA=="], "editorconfig/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -4360,7 +4338,7 @@ "html-to-text/htmlparser2/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], - "hypercore-crypto/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "hypercore-crypto/sodium-universal/sodium-native": ["sodium-native@5.0.10", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-UIw+0AbpCQRuTJF88JWrZomP4O+PXhlWvdopiAJOsUivTyHTf3korMyStxkZuPngSbBEtEfDdc4ewEd8/T4/lA=="], "jest-cli/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], @@ -4426,7 +4404,7 @@ "nodemon/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "noise-curve-ed/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "noise-curve-ed/sodium-universal/sodium-native": ["sodium-native@5.0.10", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-UIw+0AbpCQRuTJF88JWrZomP4O+PXhlWvdopiAJOsUivTyHTf3korMyStxkZuPngSbBEtEfDdc4ewEd8/T4/lA=="], "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], @@ -4444,13 +4422,13 @@ "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "sodium-secretstream/sodium-universal/sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "sodium-secretstream/sodium-universal/sodium-native": ["sodium-native@5.0.10", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-UIw+0AbpCQRuTJF88JWrZomP4O+PXhlWvdopiAJOsUivTyHTf3korMyStxkZuPngSbBEtEfDdc4ewEd8/T4/lA=="], "streamroller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], "streamroller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.18", "", { "dependencies": { "cacheable": "^2.1.0", "flatted": "^3.3.3", "hookified": "^1.12.0" } }, "sha512-JUPnFgHMuAVmLmoH9/zoZ6RHOt5n9NlUw/sDXsTbROJ2SFoS2DS4s+swAV6UTeTbGH/CAsZIE6M8TaG/3jVxgQ=="], + "stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.19", "", { "dependencies": { "cacheable": "^2.2.0", "flatted": "^3.3.3", "hookified": "^1.13.0" } }, "sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A=="], "table/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], @@ -4522,6 +4500,8 @@ "vue-apollo/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + "vue-i18n/@intlify/core-base/@intlify/message-compiler": ["@intlify/message-compiler@9.13.1", "", { "dependencies": { "@intlify/shared": "9.13.1", "source-map-js": "^1.0.2" } }, "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w=="], + "vue/@vue/compiler-dom/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], "vue/@vue/compiler-sfc/@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], @@ -4578,7 +4558,7 @@ "jest-worker/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], - "jest-worker/jest-util/@jest/types/@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "jest-worker/jest-util/@jest/types/@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], "js-beautify/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], diff --git a/core/src/emails/sendEmailTranslated.test.ts b/core/src/emails/sendEmailTranslated.test.ts index 3f8b5680e..26f4d6ebd 100644 --- a/core/src/emails/sendEmailTranslated.test.ts +++ b/core/src/emails/sendEmailTranslated.test.ts @@ -41,7 +41,7 @@ const spySetLocale = jest.spyOn(i18n, 'setLocale') const spyTranslate = jest.spyOn(i18n, '__') describe('sendEmailTranslated', () => { - let result: Record | boolean | null + let result: Record | boolean | null | Error describe('config email is false', () => { beforeEach(async () => { diff --git a/core/src/emails/sendEmailVariants.test.ts b/core/src/emails/sendEmailVariants.test.ts index 74743dbd9..86ec556e9 100644 --- a/core/src/emails/sendEmailVariants.test.ts +++ b/core/src/emails/sendEmailVariants.test.ts @@ -1,5 +1,6 @@ import { Decimal } from 'decimal.js-light' import { CONFIG } from '../config' +import { mock, jest, describe, it, expect, beforeAll, beforeEach, afterAll } from 'bun:test' import * as sendEmailTranslatedApi from './sendEmailTranslated' import { @@ -25,7 +26,7 @@ CONFIG.EMAIL_SMTP_HOST = testMailServerHost CONFIG.EMAIL_SMTP_PORT = testMailServerPort CONFIG.EMAIL_TLS = testMailTLS -jest.mock('nodemailer', () => { +mock.module('nodemailer', () => { return { __esModule: true, createTransport: jest.fn(() => { From aabc425b519fc5355b061805a8df621286e32de7 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 23:07:32 +0100 Subject: [PATCH 168/226] solve forgotten merge conflict --- backend/src/graphql/resolver/TransactionResolver.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index b1e9df019..b53ce4e61 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -33,12 +33,7 @@ import { Context, getUser } from '@/server/context' import { communityUser } from '@/util/communityUser' import { calculateBalance } from '@/util/validate' import { virtualDecayTransaction, virtualLinkTransaction } from '@/util/virtualTransactions' -<<<<<<< HEAD -import { fullName } from 'core' // import { TRANSACTIONS_LOCK } from 'database' -======= -import { TRANSACTIONS_LOCK } from 'database' ->>>>>>> refs/remotes/origin/master import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { getLastTransaction } from 'database' From ce9e256a79927e5ed0ddeaa6feae18aa0f1a01b3 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Wed, 26 Nov 2025 23:38:33 +0100 Subject: [PATCH 169/226] correct merge errors --- backend/src/graphql/resolver/ContributionResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 4df1b9cab..6a6555c84 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -43,7 +43,6 @@ import { import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUnconfirmedContribution/UpdateUnconfirmedContribution.context' import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' -import { fullName } from 'core' import { calculateDecay, Decay } from 'shared' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' From 2d1149232f1d69005d9f844c4e45df87ea7c8da0 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 01:14:44 +0100 Subject: [PATCH 170/226] add redis container --- docker-compose.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index aeaac0c60..18c4d6feb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,6 +76,18 @@ services: volumes: - db_vol:/var/lib/mysql + ######################################################### + ## REDIS ################################################ + ######################################################### + redis: + image: redis:6.2.6 + networks: + - internal-net + ports: + - ${REDIS_PORT:-6379}:6379 + volumes: + - redis_vol:/data + ######################################################## # BACKEND ############################################## ######################################################## From 13657b82c95cf2db017d0637dbba7e732a6b9ef3 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 01:29:47 +0100 Subject: [PATCH 171/226] correct redis volumes --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 18c4d6feb..f11619c31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,7 +86,7 @@ services: ports: - ${REDIS_PORT:-6379}:6379 volumes: - - redis_vol:/data + - ./logs/redis:./logs/redis ######################################################## # BACKEND ############################################## From 6a9cda75ef4a6b107f18b91c7250274056dcbcdb Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 13:56:42 +0100 Subject: [PATCH 172/226] correct accessing redisClient over AppDatabase --- .../graphql/resolver/ContributionResolver.ts | 47 +++++++++---------- .../resolver/TransactionLinkResolver.ts | 5 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 6a6555c84..167677152 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -1,8 +1,9 @@ import { + AppDatabase, Contribution as DbContribution, Transaction as DbTransaction, User as DbUser, - DltTransaction as DbDltTransaction, + getLastTransaction, UserContact, } from 'database' import { Decimal } from 'decimal.js-light' @@ -10,26 +11,7 @@ import { GraphQLResolveInfo } from 'graphql' import { Arg, Args, Authorized, Ctx, Info, Int, Mutation, Query, Resolver } from 'type-graphql' import { EntityManager, IsNull } from 'typeorm' -import { AdminCreateContributionArgs } from '@arg/AdminCreateContributionArgs' -import { AdminUpdateContributionArgs } from '@arg/AdminUpdateContributionArgs' -import { ContributionArgs } from '@arg/ContributionArgs' -import { Paginated } from '@arg/Paginated' -import { SearchContributionsFilterArgs } from '@arg/SearchContributionsFilterArgs' -import { ContributionStatus } from '@enum/ContributionStatus' -import { ContributionType } from '@enum/ContributionType' -import { AdminUpdateContribution } from '@model/AdminUpdateContribution' -import { Contribution, ContributionListResult } from '@model/Contribution' -import { OpenCreation } from '@model/OpenCreation' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { RIGHTS } from '@/auth/RIGHTS' -import { - fullName, - sendContributionChangedByModeratorEmail, - sendContributionConfirmedEmail, - sendContributionDeletedEmail, - sendContributionDeniedEmail, - TransactionTypeId -} from 'core' import { EVENT_ADMIN_CONTRIBUTION_CONFIRM, EVENT_ADMIN_CONTRIBUTION_CREATE, @@ -43,12 +25,32 @@ import { import { UpdateUnconfirmedContributionContext } from '@/interactions/updateUnconfirmedContribution/UpdateUnconfirmedContribution.context' import { LogError } from '@/server/LogError' import { Context, getClientTimezoneOffset, getUser } from '@/server/context' +import { AdminCreateContributionArgs } from '@arg/AdminCreateContributionArgs' +import { AdminUpdateContributionArgs } from '@arg/AdminUpdateContributionArgs' +import { ContributionArgs } from '@arg/ContributionArgs' +import { Paginated } from '@arg/Paginated' +import { SearchContributionsFilterArgs } from '@arg/SearchContributionsFilterArgs' +import { ContributionStatus } from '@enum/ContributionStatus' +import { ContributionType } from '@enum/ContributionType' +import { AdminUpdateContribution } from '@model/AdminUpdateContribution' +import { Contribution, ContributionListResult } from '@model/Contribution' +import { OpenCreation } from '@model/OpenCreation' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { + fullName, + sendContributionChangedByModeratorEmail, + sendContributionConfirmedEmail, + sendContributionDeletedEmail, + sendContributionDeniedEmail, + TransactionTypeId +} from 'core' import { calculateDecay, Decay } from 'shared' +import { contributionTransaction } from '@/apis/dltConnector' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { ContributionMessageType } from '@enum/ContributionMessageType' -import { AppDatabase } from 'database' import { getLogger } from 'log4js' +import { Mutex } from 'redis-semaphore' import { contributionFrontendLink, loadAllContributions, @@ -57,9 +59,6 @@ import { import { getOpenCreations, getUserCreation, validateContribution } from './util/creations' import { extractGraphQLFields } from './util/extractGraphQLFields' import { findContributions } from './util/findContributions' -import { getLastTransaction } from 'database' -import { contributionTransaction } from '@/apis/dltConnector' -import { Mutex } from 'redis-semaphore' const db = AppDatabase.getInstance() const createLogger = () => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.ContributionResolver`) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 7d56a7925..e834ae305 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -85,7 +85,6 @@ export const transactionLinkCode = (date: Date): string => { const db = AppDatabase.getInstance() -const redisClient = new Redis() export const transactionLinkExpireDate = (date: Date): Date => { const validUntil = new Date(date) @@ -241,7 +240,7 @@ export class TransactionLinkResolver { if (code.match(/^CL-/)) { // acquire lock // const releaseLock = await TRANSACTIONS_LOCK.acquire() - const mutex = new Mutex(redisClient, 'TRANSACTIONS_LOCK') + const mutex = new Mutex(db.getRedisClient(), 'TRANSACTIONS_LOCK') await mutex.acquire() try { methodLogger.info('redeem contribution link...') @@ -403,7 +402,7 @@ export class TransactionLinkResolver { return true } else { // const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() - const mutex = new Mutex(redisClient, 'TRANSACTION_LINK_LOCK') + const mutex = new Mutex(db.getRedisClient(), 'TRANSACTION_LINK_LOCK') await mutex.acquire() const now = new Date() try { From a9f5b9a6a0fc8e2be9d912fb064bfcafa8c9717b Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 13:59:54 +0100 Subject: [PATCH 173/226] add starting redis --- .github/workflows/test_backend.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index f85fdfa4c..4098e8ae6 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -51,8 +51,8 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: docker-compose mariadb - run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb + - name: docker-compose mariadb redis + run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb redis - name: install bun uses: oven-sh/setup-bun@v2 From 367e3b0b6aa759a32c80b8ca2d91a8ac6cbfac47 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 14:16:05 +0100 Subject: [PATCH 174/226] change redis default log path --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index f11619c31..4d305b4bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,7 +86,7 @@ services: ports: - ${REDIS_PORT:-6379}:6379 volumes: - - ./logs/redis:./logs/redis + - ./logs/redis:/logs/redis ######################################################## # BACKEND ############################################## From 4ea54913871f582f86e16c510730987f11870a80 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 15:39:06 +0100 Subject: [PATCH 175/226] invoke docker-compose redis separated from database --- .github/workflows/test_backend.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index 4098e8ae6..7a1eba2f4 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -51,8 +51,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: docker-compose mariadb redis - run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb redis + - name: docker-compose mariadb + run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb + + - name: docker-compose redis + run: docker compose -f docker-compose.yml --detach --no-deps redis - name: install bun uses: oven-sh/setup-bun@v2 From 5514bd217e7186400d5c2b130680c98210134e49 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 15:41:57 +0100 Subject: [PATCH 176/226] remove --detach --no-deps from redis invocation --- .github/workflows/test_backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index 7a1eba2f4..664303533 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -55,7 +55,7 @@ jobs: run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb - name: docker-compose redis - run: docker compose -f docker-compose.yml --detach --no-deps redis + run: docker compose -f docker-compose.yml redis - name: install bun uses: oven-sh/setup-bun@v2 From d9fbe81b976002ce38b11b554be575e6c0074551 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 15:45:36 +0100 Subject: [PATCH 177/226] add command run to start redis --- .github/workflows/test_backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_backend.yml b/.github/workflows/test_backend.yml index 664303533..b5a4c2c90 100644 --- a/.github/workflows/test_backend.yml +++ b/.github/workflows/test_backend.yml @@ -55,7 +55,7 @@ jobs: run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps mariadb - name: docker-compose redis - run: docker compose -f docker-compose.yml redis + run: docker compose -f docker-compose.yml up redis - name: install bun uses: oven-sh/setup-bun@v2 From 9df19380710331b1596a827afbce26aa6824ce38 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner Date: Thu, 27 Nov 2025 16:02:09 +0100 Subject: [PATCH 178/226] start redis in detached mode --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 4d305b4bc..498207c3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,6 +81,7 @@ services: ######################################################### redis: image: redis:6.2.6 + attach: false networks: - internal-net ports: From c0fc3ac089ea2c9447cab13baf9822ca6374e8c2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 27 Nov 2025 16:56:29 +0100 Subject: [PATCH 179/226] success message on contribution creation like in transfer --- .../Contributions/ContributionCreate.vue | 37 ++++++++++++++----- .../Contributions/ContributionForm.vue | 9 ++--- ...sultSendSuccess.vue => SuccessMessage.vue} | 19 +++++++--- .../composables/useMinimalContributionDate.js | 5 +++ frontend/src/pages/Send.vue | 7 +++- 5 files changed, 53 insertions(+), 24 deletions(-) rename frontend/src/components/{GddSend/TransactionResultSendSuccess.vue => SuccessMessage.vue} (57%) create mode 100644 frontend/src/composables/useMinimalContributionDate.js diff --git a/frontend/src/components/Contributions/ContributionCreate.vue b/frontend/src/components/Contributions/ContributionCreate.vue index 3dd5a8ca5..e509ed412 100644 --- a/frontend/src/components/Contributions/ContributionCreate.vue +++ b/frontend/src/components/Contributions/ContributionCreate.vue @@ -1,15 +1,28 @@

SFWk5HPhj0PxvS-s))FK!NEZG^sN=ajxZ! zO!PwTl*-f~vlcrb?&@0^VT#1;k%pT}($pnuSb*Th1#J{W|0}wfiWdKV=^8n941FP5Mr2VU8@#&dk_Zar(k++ySUXS>vyz6aGn;2I&=nX4RI+ zE&Y`IxWhIjMe+*2q9(Ia%J$0$tP-H~Ov)r9S1he8&ZW67_f*1kj^pC5sAaGzChIfd zhE(jdU|a0s6;2OOjJ#8G2u^H$NyHBi648m`d$qZ_q$L)(rZI-K7%@7zT!*q0^kYOU zh%}VqcLkz*Mh_3Nll&l(ESTDWdep8ah*4N!4Kmw1Ct7KQQsyGpnUk^VQpmA`KzA5R zOc#z#AO>>?!W|W_;Q|ft@Aw7(03dZW;MCiVoEwI`4EPOP-#25k23JA}Xv=XGtL!&4 zj^lwQpFYII@(E=&7>CJ>TI50mhOxgG%ko4DL}y6Q6d-O{LBS1B;kaTxuZ{w>!L`Ha zN!Yjzr=iP%y-Wv7$GW3?akOo|QB7CVGK+gd5UVnm_n?}Cq;EW3$!**{xMrh>)yW3t zqIseVW}<^3Hm`D#oh=ON#6h*p7ZkgVXHa69?Hy-7?v_MmE}7rLF&YM8%4%ZZkZhI- zQko*3VPXSS?38B)l?EXRNAV@#BN9Xwm=L*&%iO?*C!#Rrc*Mhn0mFBig+;%hjVo4g z5YFB6nuw+c`iJJEzT*eMA(Hf8QjRwQY=^R2H_9m8gquNQ@M3a1i~LXOz`bE*=Py zveB{q2*tSUf3RGWxn>=IqF5NXtE%JaD0IBU4nSu3lES51wl5fFCPrd4HtYK;F>t*i z%f;vDQE>~g+^#VBUg`j#e$4>;2A3LwEy^D=e#-i3hspFB5n>jBrhV~GA_E$voZOHJ z+5wnoO0AHZi4$`I+h>uH`Yxf`7&Lb~7v#!CX5GWzLuff6z6od+GP{LAhDeFki|t5F5FQ2LZOg=0#)1!{%~LOR244a-wyZ-M@ufeM7}4PPg6PBou=$8p(pj| zsZl9S+(5X@C1l?nN|(UMpo7 zik2CQ8Y(GDcO(F-fkR7dOzd0=DXCjD#)oND>IRbBx|PFNisQK8L>PfT=Ba;TQ{=~_ zvY{im!Ks)fWZZ9tI}=kT<XfO0Avrh=_~G^lE9@P9Ts#E zm5>s={{Uz?m`zTgQhL8RM8_99C2WG=nzS-tLsP%!ZT|qnSVO)Y^7ozj?Jg6uG-1mq zGt>vrZaC_8{w=(1QM0LYZX_BmC^Ss$m0=Y(>Y!nx4NMbRq`=$_%n)iiGCHY3x_pZ5 zF>tj+eFINZBT}|-EmIw4G>r2ejU;&tyNO-g#F6uHYB(;YRbf#bXr1g|x&vYoH@)y{ z-lNZ#;9`yub)kESRwrB8NA-q>3kT$~V2*u}FyhU)R*V)B1=`}hOO!^JetIWbj0;lA zo8CFZD7z|EK3SZI%T>V#BCZxYAt4UpTM@`bsRv}Y(!=r(s1^E#1j5${)Gpq)EF?cj zji5@cG>*$c;;a^~Iz~H0Yq<}Tw4%bK{=y#2QJ%q@EnHZJXXG*)0}<33i%*v*8)3|1 zV2Y?f?YUm5l~}vtQ}?x*{{Z0=K8crWbP!_C=^oV(Exf(|06TB~SDiT0Z2tfY zZXMol`?N<+=B4~iuOmx0Fj`m1m56vsQ>=oKlhie?P9=xvsY6~*gqS7@%*iy~Ja-lF zPxD?l<<=0`{{Rg%mcwv)!{7+Ec z;5M(Q%mMahy`rSHG3sVkzGc-ha~d!~Cu^7{p{rpdZe=0>YrYXmk5KMR;VoMqkf&$X zW6H~kF5SS=L?9NUJro^laaUkin&v*Cy%xs^6%4+G-*HPMcLLTrMFZR*tWo`mniquB zrw_iuE3H^|jUJ3J?$LW83x=R#V070M5EVC_BmV&AI~rERCTubmJL=nvA00*i07w)z zH3zgRCYVvf6Z)B{U0n7_rwvZvHgl2PVPpuUI6ZE0_5Yv$f~6XwVzN@{&k4YL4P(K1CNA(@`XvVt>y zEVW>bXNG5{ZaLiim2zm5c78zV_+eLrXzt&+c39wYmhvHqh+Nn@l|zamjOtMeEO5{? z_wf+a0f4r7Rd+{MH2rxMA)S|xxN z#BB3Bos_HlDWvMQGd;A*VWAr)P7b210uAgVRWHHEsR@NSQFz-k34Y01f)8K95!7f} zfXg0Neat{M50DpOg@peA3S1q4^#%J(Fhv{09>}XHl0|nq_D9k3ju9&ZsZ@2s7rA7! z`3>+fac3*xuLFp&$+9?XjF*H{b}AU#s1pAGV7jrC9-D)6-eZYmvx+@NRg*P}pK_sD zhQz^YwJenkxA+hdg}89^W<8K*3vESGs5dU(?h!Y9fp{4+D&FPe_fZR|$qT52UKwAI zLw6`jSGFUoF-FrD+$n|`sQK9dA0^I+Sc5!^0h0zTEzO!2D6?rRsh)tkgj&CNKBR~X zGaq=7^dOPG6IR^4Wd zq{7s5IsoD|$9Bf5Nf2%tCS0}D`l41b6hvS*^CLs=rWWg!ACel``w&E)btz=rA;g5) z)A)$K2k(f6c4oR3mjtwsz(|R$qfE5;$v#nQxpI`>TSQ%?)L`S1@H{0k88tjI#b(>Z zQ+`165*X5V&XTI%TLuM3w8WW#?pao5Fjs-Rn6_2@JSAW`9`mo}H~#>|)YqLkHgO|% z8gTE)R-a`|-TwgKMTM)Gt~d2k?+H)xF{1|qQZP0{72RopOEhR`O3Nm~AyY}*Cn4Jb z5(a=`<~BCr3^maJuJJLlRZ2D`un|KLmGw2wkR z{Q(p(xKK$E@R?mRBAg- zReFwubeF47X;2$So6mw8LEsplghNol#im5A+I&D%Znz)JV~h~Cn}LB8txbmzhQht? z0l5^-k?QAx92iCBCTXxvaWqg6sC00Sl-n^XBx{zbXp+*>($QvL489qBIMpo;O(nQ) zl*KPqF@moJmQrfwNL;&rq8kUPk|F68u?!s1nZIQ#64IkGn80U70e+wswWvVK_VeVlB(VOMLBjFBMUrq7A5PWKy8+VX}b2%Ul+&F2m^nFa@HW zadd)3ACj_vOdPO*KNuNEnl?d1PsqYz_bWx}ALa{Y20GlQf0W#8!+|ajt`!!p+y;#| za+j=1TQAs}V$R8HAiklxHc9}B?kt)7lrsxb2wtPN90J-c;M`zJg#Q4kMZ(7AQVA}q zbeJ7#PwiW2D3<j0avMV+9x zDxe{O4(vf!^hI3s7m(ged=p!VY+s7ByB)c^`T_L7HQVD}v(FmAHVqkHL*S&wLth-Z?L%3TCY#hE|5WI^hH zwk|u{wIwJNTu-D-FLPM@fip@}rwge`Nk|tA@bPi}9c947aN-s?xlB@!A%ZEA`kz6F z)M6BTnvGmTYuvRIxb7Usr0#bX!e+US?@(V0@=vLIm=-ZZ+Ax^@=ElB=uPp6KfX3A; z0QZ$PLjM4`7GSmGxr20d1c&w1c%-BX`5~Y_kpWnhHP%6LrY@Z@BIg8TJcl4@_=ZqcKGXcFAqds_ zdqso=2TA%+hUOfe(-Qfo*z}k($bgvt08HUTbK!%4I<#{$BW~t-QB-MlDmq9zn*w0D zR|}bZH2VF`$`6M3`v3q$yqwZA!>r8JQ&uBJV$WvkA5dFM_Y$5F)Tx!m+B zCBv#f=`FO@H7G>95OpCxaD`*0C*52smO@z9SWu{r9z~Hr-*M-B2qwsEORF&;>C(ei zQJAzQ7689tET`-aaD7EkKCW9FS5qQ!&ju9^rQyublM>Q(Ke!b`vRMpw_zVxIUmc{( zJxp1sBGCCNW+7H^?jM+SKfBT*(PBYion3OQ9?r-^RSH~8Dcr$it=?nau@e#BQ3fO2 z2)1<*?73|2NchCm8OZq^nqpEDGXDT^9PGolP0T$E4^gOg@TFj@0X8OuoqbPAAVKR8 zB}3Uxc=x%YGI}KvWWm9$N97D~JL+6Fp>nIz!og(x!7H6=3U0=8x%f7`p6GNMT3!3g!P^A2W0T-BvVy707H^i4NT(~)l`7T^_HgKZDn`X%QHE^mZjGRl` zZ0Ix-BG<=3QqM6LK=Lp62~(+6Qkc}J?~3Np1Or7)P8g_OU<9Ea($1>Ua!VO>)=mMmXoSN{N9q)WiX6Bn!}(hFWH z7#MXoa>c73BO)QLK-Q{(>=1D!EL(~B%c{Y7z016e_bc7}n0xzR;F4Su8UQ?xojmOZ zthOD@78x%wvC~bGoM`TJL2dvv+*j0MU;h9pzNDB!>Jq|Jag{bt7L36Ax}f-0DxI2% zZUF3-J>HQvLA%86O%0-D4aiCV047*-IfQzSD>FDH1q+~_)dzB**+s;zXs)M#K*H@o zXj_34&-MVrzZhj0uwKOelPpD*2wI-t4|9=?U^0RM%9TfUM;ZVffvE3@Jesk}Pq8C% zgkdK~=)U1=HNRnuCA)!c@VHi#Fw+C>1NJ3`w4>x*27X78d4U|4UQUXHeGx+VjVj=l zrUDvaNt^iq1%t@7$hXPDWO6b&iZA>iaCjbkLnKwq2*zB})qe<#R$wIbi%S9{Lj<7x z;oMq{EyPmb(F&Gevnu6E7or6Q4x(F5tL`XoODGY{If^wYA7VQI{{XBta5$y%vy&)L zdHHh0K)^tfhPFz!MQ&O`1a!dYG_Ex)toSPwp&PcMyGmf{B3V zA#thpQAMCE`7nRbnWsIBKFzoiJGt$ROaTCk?*<}@utwqdVKXL}G4x8LyGcy5(>FJx zZMdC}ju!PY-1_6m^l*`_agpj?OiP{=;w467QYdBALuu&*z|+M?nV4jeU=DRfez@Lplm7r{L^KHFdw|PxA;BOtYt%;&C$;{G@vYpmIA%R75|wY+T{>o<%YOU- z)iG%7#3g^UY|w>Ms4O=Et%kM|+JMeljFyR37%rtm zDntDGLKk3aEsfew>_G@*s9Y|i)-kG#M7|UpBAtQ+gXFnyQ=C8{MM1q;4yElo)Y`*1 zHG)IB8jhnc_=6UqbVs-n)3^>i2!nHLfQR%<6?ur;A7i!Evl-71g$XR9F}*?l#XT@k zj=rbhbS;wKW1URUG>=wr`3`g2hLYL_?STeQXoZ`!r&P>`C<~cogAd^VI40kjk_IDK z;lBy08k=*|`4O+?bvE$T9dX$=^RjO6?G3TY^zCs~*%^LE{BiHVPvE3$_%CJ*X}vJH znMXQOA|8ep7w0WlVW5Ac(7nUUNvmpE9!wodO5ZD~S_Fep^o*0`mZ1GAGPfFqohl-uQH{=gO#-%7dovU2b;V($B%2I4RYhk|Ktz{+ zvr^C*2!>NkRH>-|+n~f&N6|BbB^Vm3 z3WH1J2thWe@=|sdJD*aFj1g01s%8RtS~L%$Dn}WXJ8AAYZeGB6BsyfqttYYNsmuvL zO#Eh7>9ELQ*%A58$h!*e7rkjn%oXr3JaR=SF3zQ6Du$)N4a!Kf1_`TLYFZTKQ@xQv zp}5VzWr=rXKTyHXUK1T?+1voa0Z<5mt)OOdn0af;Lr0>hY;|$21M*(9uO;pjV6v9u z)hjGvztlUMm3~Ide`Y2s4PhHcP{f8G{HOvC<^j0d!vQYNH!K_ExTrV^BBgSITH&U9 z6$W!G7^Uc0mQA+<3#W5=kkuKL6Dg@g7NmSDfoMT*M`QXZor>RM9-|*7@Ud0F4qWK& z81ZLu>S);&AW_UK?ru^PEnUJGsg+cGOLk2{!A~ON)WMxM42!>IYRqJy@-@=0G)xaq znSdCv3S+#)C30?Fn9AmQ5~_9E3fo2MEh2_S8ZxLk#(RJhw4kF1FN|c|sJ3OVdlAD2 zn6&)WE&l+eI%x%1o0%0Ow>JSD*#@Jf$p9zZUJ3CtEk&0`qT;Xr05JTW{bx!L>N2OO zY!FRxSiU|yAu_wU)PPeElR>(gOS8fkMoD;{#NVeN*M zXb${qj;{l+?K3=`e_<9|7X~amLke4n?8+eA%QYJ9ncQ-s#Et2R%~h$gPECwfUM)&Y zv|(BqA19+x$^QVcDs#C46;D$*kS^BmQzszwk*Ep5>JGHdjqMEm?$py$Rf3a-xkQY$?<; z&?Qt$nKZ1y64x_G2H~A|SbtECTbvbQpr*-6ZQ2e6<-tc#cs|X!NN2Qtj6#U%Y;IWj z2lJ?5nWzO>LaIjN-@$?YOBi-kpmOk+Z@7>d)Lc#p6ImvsAMnf3_fnhArbNJ$)GQRY zfbpGtMNd#aLr&R}XLLsY0AY|*3+^xU{9{nWh-^wrzODZN{#-#H2Xg8w*tIswRu;hq z9+@*v?&tQLhQH1&{{W2ZiN0+=nHxB2hPfSog})6RW#ofpC;dKB$FS+ z2lj{GNn8ymjE^w7A%c&_44%M5BP2jjO$Hd?nc*=tKp1Aeq67w2a@ywQ3$oncTS~yC=_YprF1U=D%!FPQ~>H#pQX4; znK~h$29kE(M->G6qAP%=4pPQXTS=)&NTwKy8;&B5A=4VclT3X&%-%<=!@?Mk&6sOZ zOxVg8OJu~Nu+==98D1b(5veT8ylWN`^{zJ$Ky9HAk}%jR|u##f_24gvt??wi377jrbfhAMY_HnSIz}yZ1j^Pjec@{P#n!}yS zL^p3Gj9GGnX{rdeR8i8$G(|)#ICT`8?H9S#EVEA72H9W8=|*X6=TkUc6quyU9sdAv z9=R8WWFFXJ(!Qn~(+RX^Da=B~@R4DY{{WKOI0uENlTM%@$lLb;QygGFAyg<(sxAV! z6+l!dHT(e)z$!a)7<5Y1q@)Z=NMYFQ2lrD4UyPp2?OaFC7X*m_2s zD|0?(a1jC#nbEj(#$sQ{s}nJZq1FB+Zl+Zijd7v0@hrSrnEwFwji=B|H9FyRB_1^% z;)t8-A0@8kTil|}Kp|)3*mn=17budz%o7b05iND zIFVbwX)B}O887<*O(=}3gc)+K!?)ueP#?K*90=g01gBzHGI;5X&a7!}14d&(Se}x1 z8qhB$dB&zaL^_26lcXU4r7&5NFV5!A9N$H z>>qO|{qE{->Gb9)=-`gI_+tpPmiwnMN)@tF>cMEqwIkeY=p}35iob2}gvut~BOc_{ zHRslC!yW~2*FRs$q|=n=r}LE$?+R)xD)u2z>T3_v8UBs{flK*F*}&YuhJ-c}s>VD( zva`F#iBc)@R&IiBz($d1A)Dl5msH0s@G-754SB*vxI((zLAk}G$7E2fi`vSTedbh% zKFLUS%R#7t>Bt4lfoJ=gd7_NQ1_i9h%QEMJE4zBs(r1g-B)e2tkTow~gKH8hTA0QF z%JT%IR_ZB5d_;IHVpIbqNRBg4UgKcPw5M@iJ%U$P4Gc|t zJg??kB8{esDv|0QmHz;6OQH!~i z088=V;}LGyoiObTg<%nbQD~7VeFVPwGNBNnFIfKLa>4KHE{g7=_)&wXpSsFu6Cm<8 z+l)~9N}aN|0G3vz@PD!Y08SDPi$SSOX6|?qaK>AcbVMVLDYSJK;)@aSS%Zme##$~V zv0`5+~Wv+%Ef|$5IL=7xL+%SL)UBZBt6^zY< zHy;rS+Ym@?pqlB`EYSRsiQp(c$d3adD|<}L?MCWoM0#6sgey*5jJnw;&^U+O_J#_+bsPg zBzGvf1A?t|l<7s(>(x{WN`=}D?g=S~z8~1G5uLM9RC<)B^zMB0!z7-rpC#-BI-A@l zSoFo-Fz>{6=Y&@(Kh;mf!e{&@H4X zRQ4_%%Kbf%hT&4YI`$`88yzvw=9Tfu961H2F}&-IBG)De)Rsk3?Bwj^C}nUeP5nuR za5DRN%f&c~#*oakF{r^BY}^%^h^UOEvhU)m{Hw~-__bpwDvx4H8yF;LMic3P!U=*#Az6uvln zBE3wD`A`8i6&}$TQDVJHb>N&L4&`8V?DsLoFhuVOUGpfs#tf2vwH9GC2Js(K90VWR z>6I>{U@+j#_7UzCF7Of;tHfwS1FG94C~B&VHl=2yP|P04?g-SqYgtsx!4az^vBpFX zN*=IkZPrzrn-xZ2{_-#g!m43n#lc6WUsyXJsjH4e$WmBYY(__tRklV ztO+Vx`iJgj;v`9Ftbf4Nd^=(CFWyQyiKchq-b&|Z4>xl@FC9heY zL=g?v9YSsM{otx{lxe&~>NX}sA&|;D<@P_0?;S;#1%JYt<4LzVO`JD}I`iB3LYwo8 z{{Yi6d|WH5P}SypQY~mgxB~BC8AmpY*{T9f;MdaGuNbI$TPh)ilAP z$?5SoBEXBwl%@MFWyj-*SpnTdQ`9KTNP`AV`j#*0E}h&Z%&Z(V6?sy%sL$2Mv#SvN z$c|GnE>0RosifEV&d=n%ajf1vX*O^p1D3qD{xB4>hj2M`O0&XIfG+bf#%s@ZUU)m; zZ-tF)2CINXu>6-g{{UxsOs=AjqY|W4gO&mb0h_do%O5!pV8>bIy4oy<8;ux!xH-}N)Evf}+c ziZD>WZZUm|#2Qh$$UV&SNX6fa1!d|BxW&dvHmQ@iv61142~0l4(gEw=QN1hDQ^D7H z^866};1ph-eiF>It|;nTqY+mZ$$kCj5eNY11k}Ku;ecclhFCN=;LgT`9Xl#5K->{VqDhD?LIaGno~W==7JSb8g`ovs-jTv8$nhHu{032un)D)!@T6 z%Li@7pdw8wItWHru7ut37`oZGin;Q|R8AKYLK}DfOw*5&s|lBTqsa}&Qxkw%6A(CR zMO=+02OJbt$m@(zTODx0FmM{1I2xMsWc~pS6M>rPhoR~q9YHPf)EN0#?btiu3uX}B zV=Dx9@HYlYm4CE;E5beE1=OWOGSUA4xn&AOcuwH)qXeghYA6rI-Ew;^R@s!CwXC1y>!X zx`j~=*yjUvH;3U1$NiyZ?SO45?k9|{rp7+RQq}ep=G;^jX^GfsR!gWVG9R$Ptd@%s zp?<|*_L#f{JUGrZ5@sOstaGAS!=&qtcsh92EL>L{WJezxO?XtqY`bt9UZNv8X2xe5 z*jJ${Gxa)Sz8XiqJQtFNnu;#*7H;N$bJ7PwVz(0L3^CI&Bg$QHXeL5hYbDLIKtgBY z4F%geu>y;Ld}BX}sgM};F6JkztAg>RT8*(9$+-AwFJelYxv%$&-o!i|Su>+1W#ECL zY&dK8+8+1_&*m77HR@EXM)BH<$XLtwL5Efenx-r7U@;Dm(neXNoJ0?)EDi^IY>ejTT?@LoDd#+0#DZX+FgYwkwuh#S9^q6P7cC7F%Hj zx#GagGZWbsH#+R~7S{YqaUbCoL$tz_Fz{`R&s@E&3^z}Z+6#P)Jn?5}O_Mtn5YD9r zqHsmF7*rVd>@&$;TZSIfH;8@Nls@&mL( zpmBKprgVe-j|E~}F%R(l28#M>3nr?J*=JIYaWc0cC1D!19JOL5P!~`Ps#wDadPZvY zcd>{lJ-jVg+;t)q9nYYcVtb~uyxLh2Q5OL5I7CroSso%TSuB+HEXQ%&TuUYlLg8dm z@ZfGuI0z19&^en3>p9$j8BKo6St@R*@xg_uj|01y_6LVjn8Us?TM!g5gQV0Gq`W~x zv@Iq(lnr+s65>r)5xpX1FwY^T>KOxJ7ykg|0kHCQ%hbue!tt&)sg5w0)R%@>Z*&4u zuxp2z%PWo2<12?zD&M$JFP2{By~?t*x*{UJ=nyQ6ss8}H2-J5oiSfKBR zOrZ>|uM_ek$D;1Zj)q=BiTd+U1gut*5|wHoEen=H>%UN=)FjxXmdTBg53q`K{^T23 z2`;@?mI){PiL$$M8iO#cx@N>0*0L+teM=F05wiuixn{3X**$@Vb{b{E^=sA`YbS2y z^&a}5sL-yU2SQ-qtFyV$gUF!|NUkAacM5=pN|0LO$rxj)RskxPtXa9H1j^yD$Z0!G zxYLf)PG;P+n{x6tnsKshj=3~Hf{ZJ_sr`af@m}HJE2o~H&w0)&;(%ojEq8Y_M^Q|i zOXmp#?qAC&V9;|RXxoa5bWd={^w`YvYjVO~Bo86Dmz!I0Uwe@u0OhHuOBUK0Z)CJ9 z;%9~7C|P95Bymyd-4M6~0bXyY=&ANnRH&FQolFD<(@6XO09lw%=^Lt_33T*K!GuDl zWtid_P3eJ|Q*g_dUcoJgD#3{JS5o4C*MX8*{Uxv;24>EnBMmDyE*5|LNuKpxQ7mQ# zI`OgsB~@&GLkCgx#xy-g$oj>a*e)ZCgt`yK|!9mGlHG&{IY(=CL; zRAvf^2urzfVl2U^(BVgzvBHls0MRJPid8bw{92f9!pfPcMbS)+UQiX`zuKw}{Gg(dxg3N~rv)I@`>SBs~ zl~rK&SP|$8ZXC<_n^OA&vI&R_C>)Vm}jjl5C|1)@~`p}{3g613s`rMLl*6o_`Rw!UTIx;`UyW zr^MBiRpkz;nxeUuiQeQmg$m#p>y$H0Qk)9eseHO%*X%tG@g?O0rC@dNNO(vR8 zvj}Rngv0j96`!Njz+B(%ROPsqDbA5{zu7H1Za+t($XeP`7>_L+_NcVMY4H^B4I?nl zNE~n|6BCgdRt`v>DyC%X4n|O^0{n)EfAt#E+D@gp2&(*nMd=2yGpOYus~%ts8hH!b zG@CeS2n6eVNNO%R;%c3EYy2^;X7gTKO&%Ubum1oH`u_k7x{lQ3O5>;47R-{DX<3Qdn4gp#O50&|EGh;FhqPci{>eiMaz*F2Q}NO2 z4!=x6stm>*Wm7iT7$V%r0Ft6K$Gb%nb~35BirK+`lPktK>K6{~Xf_ygDP;jog3@Qr zEiihVN;7aQf9Q@a>-j134EBxngv|(6^hJd0gT~zhxKHhoRWSWQTxQiM=Z72{qNN=h z1>8jVb4U`6Ou>iISF&iCR7Rme3$g{ADs0Y_2h?@1G`fiAX7W%EK`4;`Fy%8o?JDk2 zn3%cq63eVhK0yr(tXBX8vcIsfW=;rjGC5u&;c>#QF3{H+&EqwiMV<~k^yNfo=5aZ* zb{+_gNMhX5*n-XrOf~9Nqj4W#-O6!Ls*jfjklfnwajCd15RNfmZs1qkX&u9&P#q;W zz%>R<^!)mDFu~Y!a_%jtT2Q;4b|ckdS0^_S2-7eNXzVTL#ceF#>@Nkn?hw=&s0T_j z{35v2wd!X3?qO8!<_9CRTq>mt?8@he0vnZ3HI!?AyttGwlKb2MYi>eU_q|NDh179e z)G({$3xO^d(q*V=`5og;)JsrP+EXo?X1Nz8h!H)pU#m`|kQ-^OUD$wm zaI>L6$4(5w$@mfnD(}=(S625OCT0Vuo1U0w^r-s&e24~cA_byXj&U#MDJ%ySkHJ7- znZc!QiHBfSLlZKgx&sfm5OrTNfk;Iaw2!WyqQ12%`}RFs`7T*21Y6M%(ZPJUqp(f_ zqOGyms9;&6gHq~ET5A@#n((q~fa0b(z8a#ln>Ql_$-%5u!#<;PldO8=4O=d<3zTmi zaWr)?(k|th{U%F=vaoV>ibsROo;O+7ToJ-8l5{{)!)Wqc| zEzB=*Q=peKQx|g21S%SyGm9W;D&{YYI{yIkGF?Xlq%Tr#;J_k7Yla`8`8A9k%$rk? z;vG-1&kDUO6X?N@E$+B={wBd1V^ko{w&918#bLa#i#|&Bkn`I!A+|OV@xCH#`jCzT zyi06wGQJC(1f+mqG*)6DW!%S{ut9QJ2=vU>Dr|**5!klf48#Hl3^$0BvGFq|l`bW> za-ac7#B#P|Eg#8P5VjJSPk<*YaSM`_nCv#%OOPG?0-=}VNk ziT>esQtAj>buO0#S!Aiw84XI=M3fd|6E;g+%&{+rM8dpGx!l`-lZG$4pPN#BjGIG#ImKK=q5>W_kJFmv*_8Lr7yG+ z970`l3?gL3w2?q}4Is)?9^*&~?i^Y7G?p5QK@XjaQl<=Bn8P`n7;Xdxp}R|o62Q0r z0FiLb$7AB^1>8sz(p}#I=4?p<>Oq6H;ZyZ>6vI0cs8hoJjFb!_qYqMJI@UE#ls?N~ zK2NHjc7!S@wi&zJNrGborcPx&A?h>Cy&(R`@@XphJXFLcMa1RQ@amaI8&oA72wLQD zw;PXTcIu@D=7hbmFB_LJP?EiKAlowPaMzDntl#-Zw9}UH;iT2WUVBctbWKiMc3)1> zYGjzD?`xD%sFppL!7AY@XUa|@%xW_PA+ly1*4$SR$-zRSOY9c?^1D;c4rDGoxT$9?K{n>5O*rx+R0OUs{{Y4Ct@fD|Q7n_lG#KvXLLC`| zEPmxh6_@B(j8TZz8AD?j=W?bAKtHs;`UxJiwJx-7;HePV?aMP9iQ3Caf?!E#02Do+ z8C9Cd7gCdSgbJ}Sf?-hR8q~=}7*wt>GFYdLUuK;K;_YfYr41HeSj)&aO27eR09)PC z6TsLIs1sA!_6u<1Y6Uv00K#3DF4e=sS4FkCt!?dygZHn*^T1kwYB0L)JtSrE35Fos z{m_4K%wkwer%Bqk?7d8AQ!^qU5Ya0%kYX8xw&oCFoRYh0l_2;`c12ap_rrcR@N2;D zh@>v_8%;TH9daF?I_Y~W&GOa~54N|a?wjINV3ZJEeJ6vu1S(}o42QbrMC4%me? z20@4gQQdnwCq$w4n=rO(5T8ht)?gbm1p&~MVE_-4sFdvlKF`2P7^Ku30Jc*q;F_~7 z>Shgf>V>A~bc!NmA5RdV;(mVKK~IN}u{cpNVr0 zAF&2+$llOE*PmgzigsT-u+8-H6%(b+B0FGghslWN>A@2U6W@g7* zmxxw$sMnficyrY-oH_i=tGsSZug3 zSTi%iDD0>cU`0wQ8RZ}@g-%NWl0(@91%!|e$xjJz975QZ`3U9{TZ!7g5ax%7b{UVP z@_1s!L~*4P9%EfTna}{hMSt{RH3=B>k4e^NNQtx{wedmvmMpb?L4_>b3Srb=m{kD# zWzJpHW8ONH##LM-(Blv@1N98+Jx^t2NV*{~gS(1F25pIXHiam=NUAUzjBQ1k)pCDe zDR^^gAl~bf0HOLzyeAVNLeX)gY46$VolEu~$>}RZvYOI2p=FPNRr*Byra~S4O5E4M z3H_El2EQdiwb7Po!bRZP@1D@ z{vh8578tD^N+g0*Y5T$>|eO+=#Y zmG1&yljfpYvz|b0SSb$(g8_;$T5(A^%vv86a>mIa_vu8CT?M76vmHa_7BH;AsYC zrIUye-RwebN!-Jj#W0xxjL+I4H95RPQG}%F(vjssaCPutPyp^TXWXp8{k1bY13CWy zCIZx`)x-!!aa+v3r(`uiRKCl;G6M-6%kvpCeV5)pvi^}9j-!-n6|clyx|9f19M8@d zx|b)sIuQi~SCS9H5Z#l*Q&M4Eyu)#oGvRy%!PYvIfeIO)6e-*mx$~PsZgL>CwaJ4dtj^%7e@dNQaBFcp=BES6tkzJ= z{{V{V{0*a~X${Rkly~OqHjU?bVfZ&{C?2C6az_pa zVaTCBWgKp6l}1ST-sWw&M67Zss)cN7TCk+8T(HQkOf@Ztt8)E)Fu7oGT>Uu6oFzb( zzRdL#e4FvH8#7{eki@LaWUzfZ#4Lb;hi(PkTy-7B_;`(J1u!4!I<#XxBr$rkFkr0fa*PfhuA;v32~~}v zP+}5Zj6)Rdilu(wQ!Q%}&Gu$d6 zsJ#qFP7RnXD~_2`3q)pLAa=O!=|H0rmg$~~%f!R#GAbRhVg$np{z)FHyi}*p3X4S31p(OdJ)Y{q0-~=|IT@HSFOzour%;ZuD=GC)U<)E6vqal& zGmS-B(c~|rs0a2ZCP;*y*-dd#(p88hposv*O^Mb|tZCaXC(yVp-1OY`B_<(eQXxFs37?+DLEywu`Z7%aRgtv{-Q?_ zG@>qE2CM5Xk7a4(v!?EINZ0g_#6s-#2q-0zEgc|Wy89|tA$xtmE^Yv&DUW&yUF^as zSqLo5#P-5G7u4Kp{{Za8QJA6wIh|)pGjShja&3=ozBQ)xE>2DfwQU=f(VB0_GZJ5x>ls#aR(Tp~ZnEEwxla8gw6L%rua?=ayYc5AD zK@;TO1h+wZFr-_wYkJoM(~h%QzdfP9<28>RBS^RTKY70$&CVD_4)_MmB0MD)h9>Fk z{{S%zm}&5szrku=oK}`7Tg$Ycr%9r~Aa@cHVRwa0vPdo*24z*sRB2g-&80Kz4hgu!P2h})a}kcn0N{&3BYiRxq}FRS;CIO1 z@fyverfC>Cdk!7B?sS{Yk>tS^IGB*RxZ@QDq{s7c_AYmMl|E((t^~E@0<_Mft1Ie* zxHb<&0|Iw|od{jp8DPp$2zK{VQ7NkJ7_@zHS&rcFH!2;=9y0bNNO@(>JCR2{=eVka zAp0$Q9hn-;>v6O0=!!&5^*uOx$yV10La|Wi79A#QNf(z||8MreGNuj>TY_ z2`TtQ)SbgfF1FvvU7yHO&MsYnn2-ldQBt156=E=(Pco9T2aw!4P--2u!z$=t#|BQO zpWW2B6grC)DljnWZBYxfQM@bH9gfbY6cnuXBCQ`xeJw|8s%Bfok*BdHO?Jm@f#j=^ z+S(Iob$-m~7@jl6j5EV=D&BQQVs27-4n5Lsqc%ND9xl1Xp4HH?c)(e52L6-+!BDr}D z$3rki1{{mKggH&q^~L5ZP6bYEH7QNX{{ZTnuDHs({UsPC516>z4V#uO#3G5@CR|TQX5TjzoJNSLR-lCXiwlDUGt@hn z*&f7cM*>o!~VX@+A?8u!Da%hFTAV`va+xVE0m(x9rCCEs`C|=x0jh0TGl{nSSYkksEIw zLs%sSDx!`50L)9YKO)sFG9k}V*HYRuEUM-@%)Gr+SC*$vI?ZC>92?;EHJb5JZfO`+ zayG*dxr(k^hjUa>(wn6jKxEgjmFj$Hd9=YyMclR(ZaXkMuh`_=b4p8lUQKFVuVNdR z7?xYyvb2q*SG+$_-DJl|sPF6xS`T796w3@y)q^l)!mvAtGgcPJcbLrpqYXDGrXbB^ zAQ%4tDCBGyhuy5)q+cg!kaI_5sv5msp^ahk6(We~e1wL`ONX{Iwdk1!F&1I83t-zB zMj=HW)GkkaA&0s2DIPEf5e1ng@~kx~%{)`;5|SR_`jaHiyqKRMuulO{8rKErB@SxD z)QFxJDysX28xgFkc?B+*T7|R7HKNQX6)`p``0<&u5nE(II=O&56t9gLjGH)&v7Ssk z5^m)?!CBUa#p*%-;Wv<(p|DZo@X6ivcRq_`Fhw>W{BIuLb^ zqf@jJwSH9^OW}lqmf3Bsvd6Kxl#z-50D@Au3Yi9@kvK?(fgQzO62+mkZc@(3WIxmx zR!lWnuF_S69YTxXjKa;mpwPC(lGN_SAA4N1bx7kvl+?MKk7OB{rGKzUXGWG&I6#RH zc8XHYpu<|s-2zrCSu2U+VvGuc_u?e9BHgs&=9&uajn#T}1V!E~e}u#_^pf>|^)pK8 zF)9>KksbF>CK?uX1p>70TshQUF`hMoRDif3nS?M@O(=^TD}PZ*q4ET#p}s~^Uvt}B zCV20IRMKm}qW2io_n4lza!ec=@$JELQBho6wkA^=K%!Z|cyP5vu^5I9DC%CFCgdRj z82*sy_Z5+319P~G!F{nVv4mjSw95l^sQiNs7&`hmyHsG$aiKdRLobVHtZkW$PMZ7fnrD-{fp@efPxAWQivxRI@G zz^HOqY<_T!lcrl;%c(}1go5)Z$Xs`}XQ=KLF4F*v07iK4Gd$F)ME?MJb^bF^zqr+9 z6f=g&VlU*T$NEIO+K;&WLtI~T2OIlOH`$?9`!mctA+qLE=4(k0g+W!+5xL~d_E<3% zPJisaeyLQJw%=&Wd)X6vfh(XTr%U8O7Dn(tj?s&2H>F) zC~3KUT7n`Yx*M0uv4Y@O_6mPUZW!+|ZKw&B;x3@6VJ_dP(22Ax>Wmk=nh-LP^Mi>Okap)+-U>g zf0NiO{{RBuuA$VdxTXoU*4zcVY;`LcP1!Gw4{@GMOG!~=e~fV7s5OHxu-yjZ$m%y0 zI9+kJIu0wZ4(2y?n}M0_ERCgHXqI7^g0&^mGP`Ko5UIvxq5~!Xx@uh8A^!lVmLBE7 zEVw}29jvmW?gAYK9m~}uQZiej9tRCf+*)CXRLVOu^%N}ImIC4Zm|3QiXhCE%d!?ya zFp(hwpoQNFFoB@jW+iQ1%qA_N+2>+d57FVxcLcXwIM8=4o}fr;GVgR_>$zlMQ&4nT1N4+*q3PrZY*p zTL&ERW*A|<7Xo20GM0_%VK3=1RYuV}M$=sNiiU>miPcB>M97#lz+)H^Wj9~aVkR3U zYcu>oCI);!=pdEraKaNaNKD%dZrPhiMklagdl`v?Gq#Q{N>l#;qB&s|LcbBxH85gY zg4YjcQzI)ca>N2q)-%X|*|@=*)Np@N0}Ys7GXZ6|_XDh`RKWc20ft_QZdcYL8g11; zTr1VXV%xamMPe`*7dEY3Ok#uVRtMC>6^YaYAk=@RqJYru8=^AB1*4{00Lunj_Jc^j z^%~FPE=DVOg8}~V)=;U`6B_NoR>W9zVI^wR8qGkAWOhJpvnJxTFwE0w>K=hNm};Y7 zx5%w&pSelv6%0i=+5C6hAib;REMg1+4c}x(;V(0(U0hvRZ`(~3i}SoU|y_aIamxMMho(GSuC-4D5B9ra26aIlsZadNtp^O++tG%`bZs6 ze`CYhi~Wj|!|10R!fIR%31mSCWg&z$$E_j(N*ys01fm!$=!G3d%tHm;S8!QvdX3mD zunfbT>I@vQGF@#kg^Q>nhvH_yF^NwgF)yU7LfU{^2dF9L2AD9!V;qv%G@ehQE?4zG zM2Z(v4S`aT(KH1x&RFQI_m3~E>-!6actQ=yDj47fuPMh#+{t!uVQxG!;HznJm=L(|-uh9*=``a`EqGZ4IUV@cGe?6OaB6ACS-=gNSKci9`rW` z>L#=+7jw=MWgGQ|uWh2^ddoOvQ4$T!DYb*B6tH-~HjH4bk*d|=VHh&YfM-Efnlq;R zN&u<3QY~u)XhG?zs?=~kM;uL+ID4v=6w=C-@)&kwLlr4m#Ll!piHVcSfv`esVScv& zX|-JX93?#&AOk`JMO4R2j1Ng&t9*}4BT;{-bQ=)M5wfhP5p73vn3WtxTk+h2g6Ncl zvRmlJ7q}{u2o4%?tly9%bmZ;FU*WDa=F^Uo1e)+|HI$Cv*vk-#S>(CA4>-ev8G_E1 zkN)3MUGK*-=OWrXxIVjP(QtAPZtBl9dan zFvaTAs34qDcJ^I8O{V3gge%fptdT0M5bKF0DY0oWIY-yCC_&V;!6qi&${=Ih@1U&m zW4YRg3)IDo$u8jD?p;#~8Cd@0UFm9LG+LOOV4w9=z;KvmE)pbW(WFz4+b@tWY~Lr4 z6Z)W;x|gugrNS3#qNK8+qn@`cx5;&`0{;N&RtlRJEDl^; zStV5d0T_|l#{^q>u10(nahk+jw%i+xy+KjdSelQkfc!ngawx_16!0?_w?nu+-Q00h zK}2P<*?L)bES*GQnxEc~0;2@nvjbBwW$SR|+HrBXo-(Ez$8qduAMzefx`TKnasL2m zW+UEVv34R~eCW&A*6{1wo>4|FSI+Q}mL~Hh8)G>)%WxO~J;z>wzzEkZ>K_o5 zp9H`IDu+*Fnvd>T2@jI`eMwOqC~I*b(}MFcpsx7p$Ldf8!nTjtn<0{2wqgaX8kwm& zxlaVn^p#*0~s zqtsYc=_yCaK<{KpKznrwskIxbfIXonw0TyHthZn41L;r@kbxB)Dhl8lbrBk=n^<*n zxcN1Gvh?j*h^c8bKomWt7;;eYj8ic5I+W+z09*=1vn^&`4ZyU9hf0_55ae#v!2Y0A zZc^!~N~WbKRrwPleUnZ~f>VgO$Y-TYH5D>(~r@6lTNi9&iml+7| ztQNNGGYE=MYCti02<~{or*mFL-HCden=xgvk)Dc=ZzvOReIR2NYfVS^2Xg8dL2R=Z z5va=yEnY}O0U|KC(R`3bJdkm_yitD590@1m_M*TNzCwlC+-II1-ou7J$BQJQSwq$n z`^T>jikXkz8V{fw6p?U4$x~QmM6wW1lth z69H&m=6!iCRrAphw3{bWO%qm5$PAK6m5j#Pf*B)MnCe7Uslua?_}K&uH|Gj~%mC zB6dY1{{Zf%h(OB8)FQ_IKvM|h+B(=DDDj(aJA(G@TTtWBI+_xglvom591wg^)~G7! zM7Tr_0Krs7$&QQdTwoB|IXE!eY(N{D+ZkA`lO6|5uuS@uJ;JX^MfBVQ_1ru>h^S9f zF66_hniW__aL$l`^TD>ByTBo=e zX~ch!P!yJf;D^cktV^b)m%@>fI`n|g%m^Yde)^i{aJRsa*oQe1`*gUw%AG8ib}w}j zi)ZyfCJ0;dWr&;lL*#jg1yz_LfmqPT0X86i{sb|CzT<@Dw5#EQ@)Cc{r2cFVx4eT- zjc_II#mu$`H5`|c*tp^eI!6Qw33?tvIc^4p8;s4OkWdqT8%;RZfU_%vv^T)Qzm4s~ zX{-3!127Xu4P2e3?B6W2^X>}WC>MF1H3-@Szh^=O$U2#?4rP@^5nLrDbgI-Ppu|Kn zeI*PyfK>4OC%JrF;9!L%%N}F6`|HC)Q`ot=zCEz^GT~Hz`La8WkHv|{1he@Ftp#ob z3SPAz#Ge|M)QjkL%|1W%@Q?cc0NG4(_b{-Vf?b)50`!@llL{z|j?Buz0(OnQWg3LA zF%|y+BP_R3ch*EGV8E5$DyUN}3&c%mv>}*9g&&>NXrebzfe0=IL9#C0hu~lGP)?--R!4t9sTV$&oGrbfG zb2Q*(5W0s>;%6{hM5m~AOo@`g+^$*)fJpd864vHYC?zN&jkshvrrGC5hK6WS9WGR* z+@SPoW}d*kGsCEihGR5=ZMjn3lHoSVgE|?!O4cEj{<9zkIKKp}(M}#}YO7RD&?S|; z$17m~_oUAuwt}JzV#3Hb@ZtFpK-kJKfuP?4`!D|h(kk4TBm`wPgQ;o7(%mqR)In@a zX_aLL)OSQ8?2M1ug{jp`;IpWrh;~QCRotba`x`u4*e7UQpoSqTyQ&mwcT@VMiHedo z0zcAStx!lSGyA4z*n>u`i!>XA;DmE3(=|{uH4ITa@o5j-WP=qVKCQ5w zB3o24#aq-qKdTy;r)0*%WreQhWjpkhhzrZ8Y6;loEycampyhk0d9Zw`c+B&-?foMt z33iz%*paH)cQa<1+`;TRjT?45jet@HAzJb@zLR?WM{neEiBp!Oxs(bpDRWjQUa(;9 z0A|mVHBdH<=f>n}S18AO;xaiVO0?r-iHz=~#xa}~6!|Vy6G=gp8bH^#0wvMLwt(3yqA%0#MyttR@kgU^W~G#EfdDn49vU3_T%2 z{{T(lumMW$pNZ&;CfU$Dibn5_LX2k1K(IJ3Ge{s-E0>x6K)fjORy=*`i5jY?fOvqc zJl7k!i@3$`Rri&hg~wlxEJ>UoE>e|>h5CPrX$|qO9C#SHn5Jw^GfAQwIgMP-zl3b! zKZXL=gJiSBWovlvQ&3aH#I4W4CIz%#>hZ_LqVfrw8RYbgAm|~GOj8-x6fkVUj)Wm2huMFZ5pU|DR#P;m)L8O9fLHek$kNG^sZGWpE+pCy_2O9TGQ zj!?Ul!$p6x^y?(25?t zBUeA+h*QnsEvmYMQxF(jLc%fpM3w@6r?Wl59r3I{%cQ)5*VNt3MHR!tSeeVH$VGe{ z2-2n4#+#I8(eU(x5p@Zn(!`*_6c_#`@EG8OE*pi53bp$fL;ByDvN{Np;m1UkDOSVvQT;0XkT?y`VlC+ER11MzfYc{eF z-0)z7HnyRe@UCV8$R3i=(s?gsyN_EWs8xO95ix1%r6^ZkqtMj1$&wiKioaNsSa)E) zGuNI?gKuVMrVD~pZqR}+5|D~b2Wk?oX{od+gPS`hY@HreaK=^^*5$;wgu!?*V7WY( z^&e8NyE8SnMMKG}VG@{ka^4NGb6R5UiJ#V?gACN6IKQ-~mZMX)4_-&gwcH$~`5GZp zHr#QSMRf-0RirxmYG6l%286jKtt>Pw!Ya%cSaDFTQSKFc$FUjbC}v|O-%~3p*vMHH z#PqfG4S0zZV*DdT53!@Nm|hw-e3jDM?-v93aBOnD0gH%MoB<5_K`4RLo~<*iRgDbXq= zNij!J*aT9$^MR>}nW;6Myc!aSpy0@3>=OF0_GHvCw&${yiXSKif}r;SNTr_44XcZV zT}*AlEy;Xp7SB+GWF?zxF)RHlU)#dQ8h}mGFdYY^Zok5km7&uB9#5x*`a|-D&-=mI*5iJz5Aq1+(psa{E3;t*M2L!d1N zkhD)ivA}e*3Am|o;1(D^^fI(vaXjZPqqITB!e$ZnLVcJ^&v2O0Xp|$On&(lc+)r97 z)NbPXO`&SkP^d6oMrxUTjitfo25|xu4``(9Ecpok0HGKy9m|ltM#+01x)d8395#u) zM`=mSxp{)ivOOu5lW?{by{^#N4`U zQZj__lmN{6A|5n?yKrb*dy)HrANk54%F^6fEH_GDVtWOAH6SrlZ8C?=#BS{r_j4Te zM^my5Jd-QA8Kh|#mdvLaHVow+}m-Dct|Q+ zGol5<1fakg*HZTuY65>t1NbZ(E`+IH$X7NKwL*dKhxS7G);CipH4}E70T@1k!&&76 zTxz5)OSB5??haBc@t1LEWP<)>Cy3r?>E?XY#7#1OxUFh|t8(D^1hOiZ8I^F<7hL68WlAb$v2j`z2zF-J-7yFf z8RnR?)1hnA8Mnr4hA4wvJH$ad=jv| z%tgnu0bv`3(jg-cth7r4H#caxXg4*k(HNr-6-!KrIljoeS}4h@B^)yjE2 z5K3tm*dy=6#~g?lNW>DWa}vbOQ`{xOf&k~H93R-q)sYlaAcJ+8n}=>aJaI;D$(xo+ zs^Z<|ELRD3j4cYbf{kQc$i=kA@&pXpst9Sr0F=bJtwCWc6Z^nKUs7t~o0hi3#*A$p z6$Qj9pkth!2uQazhzo{jeBZi!=UK47Ff;}+e#VUZVus zVO}_3{{SI7CO-uOOAsmb0~}DUQpg`DHYI2$^^JEc@@<}=9+WC;Z0qi2MLB3FfmaV) z{UrsdWFZ1*LJ?G&&kO_>!&#N07$%%FLv;p~#hOywc=tAj`0AD0fn+Orm@^GcCI^a6 zWLrv@DT(wYEoMP7QY^GgtW_s!LMW0O1$8Pa<*>IQ+?Sx z>pNf6&6$SN`%4PO#2M}807s2QOQZ63>Zn6}?7{FcnQ|A}Sq1fn#PA^+)KxG9M?|>7 z?o*re%eQfQaHRya;D}!FHlx@^)=aFW^#|p8O|=J%%!%F1XeZ>hEgQ3lVq5YVbqbiaN}9|O)b)z< z1|fzBkLxhhAA6mZ9kJA3L`*?qh$dOZ#CPN}s^3=z(=wumUtoZ?@UpZ`vE2MBwJ2A- zn4k2lC{yB)VCCZ#f2vv#+&a7R{%GP4u(JEv-RRPx!uX2m<5ik}0p(Ar16r|mDmm9u8iraM(v3C|S-&1td({hG+o}fN+_R7%fc#Hu_ zax)Tg-Y;}&7GK>m`TgWa1dcl7pRGz#Yol-@yQG)jDZ*B10JPK#W|@Vt83Ik)DpHDB zgb*z42&GI2aP@&b6>_-NjK9EnED-Ix4xe!-s=BnXDKGAs%BVwr&$$u#fU9IG z9^R(&0evGn+m%BUFI3t_B7$DAKO7|D0)3HWBu?WXr-4< z{{Yr%MeQo$-73_&5m!+Is#gUL>J|{*Drewh)D)#YOH(4kC$WsBd=^m(FUIy-Uia@8|asYUBzBh8a|Si zyLS;_m>v(vq&Rsk{Z2nnbG8}ih_Bx0#^z`2!|TMX#*-QU03>IaFpZT$9&I{;N*Z@A zo~3|pTkc~~RUlgysg?Lds)F5*Lop>IS1vKcjXA&X87fvTS55xLg0}`_Y=_M|FS4b) zqO)~`z%*euM8m+yhJ?E~*M`X5%;I3f;TAcoBwTSVPiOSEGUIMF;BShlFg#ssDS>kk zgHdJVEXp7Oq!U`hENDD-MxQ9i?v)iYH-tl=7^!1{m$1s*LDIr_Z;E)(+^bIJ24ZL{ zQpI1h#0&o8=dVg7P+|cNPgs;-{{Zx+rb=@eYrFOnC~67^$&zV512ezJv$%b;K{Eo> z9P~=Y$&x2%;bk2~U~D>-Wg7s&OZ^}uGq_;ksv&mG>KF_BMuc?2;9a`BfhNqO6+!fd zj8{%5MO$+oj*JN8G zO7@LQC&C%*N)GP1G6wY(6X0dee`#612<)^yPSmq7AQV`w!a73TMsM#C)GrE@`ylHT zN+nBx#ZU!(w+dk2*@_O6C1x-#R{2d$Nr;U5m&}OXaq$#E!KWJBsBn~8iCmCC>GoZ$ zq3Fh+c{W%=oS9wQ+zlzs;Hh=uJP_h55~$%(4PZevErdzM#X53~kyP;^h0%&t81c6n z!E({2iHU)7rcf2Dm%)-3)G&Z|7}}ZbC=XPKf?}LdF)DLK1!WkPff32V*OF zh#N3@#EPD)_Gs?) z@Y$C@?*9P)07<_2z5f9D5BCsZgeo`#XE)YRpS#q=vtsfD%#n|$niWQ;)Di%7(*jbfs$$rExRY9&V55;97kQO~YWRUr#z}W? zl4U(OSaNVUis5kCQE82@8Bmeb#j%QjTr3Q)(sThaj)@NJQtF^@!1Xo zx&yFrJ_=tKr|A^1Jk3SXiMZh5H)+nGN?*OYpg`b9%Y`cJK z^+Rfg(zzlhrJN>3RkWt8@*P9M%p(LqLwGh>L3&0T>Exj)`vzIJ91}*DsfJkU2R~${ zSHy33#L_kDFr{l|CWUo2O1O}LGP1sd4! z)K#N#{#qjw+F}I>c;i`Xg@nOaM5HCLpWz=6tf9FQ8qm%PFwdndI!p}jh2)_`4e9{u zF?^S{Mu{ad4a=BnDFu6$?1V36e2~Gmo0dyY8K=j|jd@>k(Q*9<2a6a=(OuGB{{Z+2 z?ThygePau)w|GPfWn+%JJklgjjS@)AY>u^g%s}t^gH#sG|LhsIi6_3}#cc z7i=~I+|uht5T$hDXT-8oZQKY=7oh_#i6ygRcp_DSclK=~NI%}iAN(m1ZC>UbHhU{D zyrQ{CX1Qux3Wm)d=4H1oAd>$86H?#&h~0x7x|oAZV^}4(e`ps-^~0!xRT-^lMSZ)4 zVy5#8=|A!i#))V?;%_B1@>4s9MlLFPKE~kZXbAbu1|+ID*MY;sHA+~p@fGq4A_Dg{ z+`OB(m|#FctK`caOT;-ObD-~xL@(p(9cyBa8y!#~_Vlv)f-Y2LraurJHF^9;+T}<`T z6-U+@bH}K(_1g#`S=Un3wr&+V}cEvTU=!XHF3qC ziB5*Nx!kMPzl7TMZfAcd2>A=m(9513zAP*C!bf=ESsS<@wd2?IO}{uO0y92{O>jRw zOpJ^w@lY<1AtJ!_G9Egkt~HlASCxrENh9RiOt_5h#xX_xRpFfGq zFcPF-U-0ajgWM%f#4>FaJF+Ko4A0VKP_T=findUvNnjac@f`F~1HL5|VEa*54XGLZ zB!jV0Vb!ES8XoF+hN7a#?kro2aT?g|K9sg%QRG8X#$ZmnBMT{(%j@M}A!kayM4<** zo0+CB*^^6f5r?t}hv6#A+@1XzCHO;}hs}|xiVhVH8!UEoUMT+n{{YF1+PJE<%Ih#O zeSl#qg`g5H%_qrCKs)M`N|@OyF)EfDnVb_rTYn?ObPF9&2BS>a_X6$mEF3#PxJeil z!%(oM>4qtPc}yzkMp70J^(9?x5t=gHO@(1K7DEeYVx{+ z6riVbG%O{<^Kr$dHrMd5^awVibDYvW%X=owZN{u^_F$LjqljRH z*xx1k3iB#N6D?Z#0vk;;Ej_?(<_*u29J*H+qO9#Fb459z`e4O}H&gKCNVNzNmK~fW zPS(a_PA=`_#V^b=TIJpjp5xfN6wq-A{>TtsuN-^PU|ypC0FXtK zW9;;XqcNXz+IYK*5heTkWom8jQSJcg7F}*FO2FlhL-xXoJLhvEK=6kN*P?eRSJW0- zE-!;~S$B!bUJI0)_7L^P^x!V2XwfUeVZS474ofY%k9vT;^q|H|l_ww2%QzciW3$nF zEU&vTJrYe_p1FiKg0kr9=^I+`{Fvc6p$6I9q~xu8A!4G_XYip?wtkcAA`~!p zEt(OzQK?4(79!vVk zL+JJ%Q%HM`Oj1NweWh`eQmS7OU}~U&Flb+J{F((#?CORnJxM?k?kn9E&rQEMYZ__qc)X*x)>E?qLk6 z#;ug-muQ{f8KVbG5FlPStc?u8XE8GfgL&nr$P$GXpqm~uDNV}LP!Ov&%?P5*O7`2< z-*8d}os(AP7G?N77a1c8)tKm(#kTrDtH$*iv;M*s#mZlJcE!;3lL(3rOLESsn~Q*b z0|$t<8;x4=XSE`!8>TcW8nZ^CN?F{&D~|kA{7g>xK1BN^SqWQ(*n%wgDV*_18NoP5 z{h_mI{{TcT-0B$IE2cMsI8g}SNgUZ6E~8q(h;T!Vcxc55uZH~E#*hKHPzH5D4RdmV zP}v0ag&q}r3QJYtLBM8>jrq_2w*3c!lfa05%34cxbCQG~>4o>A3wbXTRlPU_7R z+DpxEX3wso8onhi4DcNtws?SO(Yuja;ayo!Uc$sc^SuUk?L$`RSC;i?a7eEjYhdtvq$QZcm zypi@lDCkFe$2dD+xO_;5DSd=?Yw|sn@cT6A)`z+O0QOLi96SC4wj1Hf;7^FPBVTeR z-NR(jGCW3HP4nUXOiTo0b5e+IHoD3!sW4a^ zxP@O{<(53acJ2=EvmNlXsCXA^f;x>g{{YzLP_Q7wwoha=`vma0I_Wq zE;Dtg7JY;ZLX2urbGcVoSExU_Oi%A7bzgAGAMb+M?d2*dU!qtO@m zJe(g{Pa(e$?Tc`xP7GsMtZvS^og|i@Jad?swwWH89n% zowA5QJj%|pRYiCjbrhP!Sa|s@$&&;#qQ4T__E{J>lL{AJ$nKj^*3eBy{6TYmljOjb z_Q2Vm`*C z$)G^()&%+RMe$#|h`;oN(S~k;&LE1k@Orl_v5k3%3~k5e0PQkDeutt8G}!3@{ng;5 zis}teWHiNjkBxUSg>#FCiKgZF`Yxjiz&)kQs3sL{cNMgBj48XK16Axjgv8e@R?tN0 zUCV6xFj!E(h=EbZWd_s1ne}fYrLictQtUeyaFD$AX43bRP_%$U=%L&ipV2TAHxZK- zxe(EI{KX(NLe8-iSIdKv@mOa60D#6s^GmRk@*qM#Gs{2W1qaw+h-q0&rY6v}%mH=E zyg}SMGM7ZpMf#e-<~U1q%*k=vHX&CpC?G;leEi7hM?O2^p5 z7a2SzJbpjKl2gfVB}U`q5ze8&Bc+Q)aHCZkbu_9KnvQ6KH3};dblC6GT=gSGfgQ+8 z){r>1qNG*V$dd7j5UkS@X#@}<20fM>K*7Utc|wo?!w1QJFfsO1p2&HHGWnPZrZymE zh#E~Cz-HQFL-t<3MNNdAM%$)X1GBkD&{-`@ZV!^_VA&lj#Ae5eqHXW&K)r^kACW|@ z;zxgj#P!@t{W~HZcPN@d7>_x^Wr=OUiDba0)iBQEmW1Ds7kF_sz@lM*)W6McbSz!6 zi-L$Qe`7!)cE+Fi3fo82N+#6AX-ih4Ka%?}wVOxjZjlZ$zsX`MFaz~wR(^~^Y=mz4 za6Jy<45o}~V*UG3FrMsYg=%Bj{D(5lBCh=tEn`GI>yg^q3j^3Pj7n@PQ(FEV%nWac zT51X|EbJH<`s11kCXRPc5B-SYy;T1IVjG%6H4pX(M0SoyI`FgFS~}ybHO9Zd8U1p1EMia#Tue=&<$QcR)LSTR&B+|WJ}2OhULX{>t-o;61A$E1ly|( zk`&+KBvEGIRJQRbi9Nv%x)@wjcwtmoDqqXAyn%@t^-=9FOk)edz==SxP}Rf(?6&~~ zMQsSQ5oD7k{vn9!0zoQND>1|wmr8{&gWfwXZOWmwa<^HUh1i)nf-~k|YA_DC>kUUy z%!VDylWfJnIKjgtbuWyJd2o3?69^wJSZfnaEzO9&++b;8(#v}&_ba^5BMkO&tI~Nf zw{tY?DU644mys?paoY`hi`Ne0_Ua55(d+{wV>uN!7KYglX*F+9m?Zrk3mJ?2VVXMFrrq|4c zPN2E76bHEPsHT#?x>3L7^21h_xsI)=Hb8;PRxiAzvmq?bX1v7)S(}b#8c6T`*qo4z z^*>5bYGE@#*r4g|471W-RNbD-PT4LZfX^qXm5~J;W0>aDx)S-zsZ`pk$jD{cV!}ib z23|cOqT_Hkx8CLlh=R&X^(t%^YYja4bi+*+gt0Q%sE&cF@(C!dW-(%ctBByv(XQn% zV{qI9GTpN)7~o2V;wDZ100<-PGpsq6>I(LHw(bF!u_|u27*sfNO-E5&aAs~5xq&Q{ zJl0J4CUMKj92awHp5lUgp_?+|okG~yhqCxG#X&8>#EHBNyv&Q#&`U+W<$4pWL;$bZ zd=#rHI(?4FJBTiqQq$514AEf*s_;NEDy1l(&!S8XmvJN--4mnb%)ivBh@O=w$Yo!t zKFq8RNDFCaG2B_{7*Jtx2va86<4YdsZWNk_X;Y80(8eKPwf0R-QTY#ICRMwbx2{^1 zz&BQ+1W#7EW{*jhD-o$ha0-}W8$f@nI+}PVOZmGKzi}1a~-K8BVHYHE9O2%+3ME7Wx?I;sgu(<;an}Kmw~QZPdINfhcaWu?4yn6eN_`d zjDL;=rfI;`b;9KSP$M_Jsxq2M}0U%VB6kIsANI#W4+zR(P`!VYcb1qH9L11sOde(~g{Y&9jmIX1Z0}@e@YA_NQtq%% zJ8>{-UNCGZAr+xySWWLXEtCw5tt|4`vX;{mTLFSaU@i&rn89UGYWD&*1YRKGqgxS% zQmOB7&_sYD-7O7h+QNN^ePh4MaL22o7LpNj+HN^0OZ}DT-9hRcz-*#7V&Q)H&NQ6< zL(p42F>_?OPd!K|nx@g!?M7B0^$z=c+|T>K?i?a?@+VckdY5;e#X1|v>NmnJM5#4o zYA%O4o!LUBRq~l){TD=4>@Ra2&)iMQ_Y^YO9Lq!h0OAR1i~+1MFyV}`-iq_r^&0;G zy_WB^N{bXJw;qLQVw%izs?v za}`$kENHz$)V(u)rh1m*z8zN+7HTjU{E1_MtOeKXVp(!1yn|%4A5(DSpw4^lH}kkZ zK8DT-f3e>XTvtnl4#WTe#+h4y*(<5siZb5SQeYL@3q#>HlHvVBHiudocitf?HDh;+>R0^NUe{{ZVtL*iqjoq266 zDt@C9>}BvpQszEkPw6vZObIC6!thfVsDHhUdFYgJY008l%UQ^Q&utDjm_`sYenti2 zKEpfGhCLiMW?&jr*n(_d$oQnPaFj(5M(B;MWtyd@v4X*b^o2{6)KOYa<;?}|cJMIM zWY!UStPzqvh18*RM*XWt(PvW1NYo?OWfy3w{hDcWfV-wxklhu!we_)f%fE4zW~+f< z%W~)32v`?px{h)Ttzx2o+`>sy2AcR~oZfeKV!5jOc>=)VyaEy%yvq)jSdqnwc9SHb`PmqRK6NT zZj`AzM%yb9ZT?FfWlEKBre)l?_#6$whaV{cTjWmER$%q6dS>b#Tshg_qfv6xD z!zhM1>SE7Q$J0n#UZf0SrqJ3r>dF5AAw$M~F^mdQ6CYxB8jhG=uqf^rOUQ{s3j;OC zH7x`v*{T{lwM4b5g~VD~a7I|m{{RyWBNt^+AQ-^5WA%KF*-sDc5wi>x=!G-vWZXi5 zEK3o11^52|BrW8CgdBvpswN2p?rg|;8|{YxnZy48*k9qB4P1Qi+1=Er!n>3Nwk#$? zfY}{Hzfjm~nTotMcl8g?44V?SWF;H<6;~I!j*e9BzY_|#qqyBTDK35JxTSYRs&^_$ zs238x(Dp+6@)Zxla5{mNS04?Mx2RS`JMKPpoFh#YXpHBcCR^o~=efNAls)+ny>z;T zSB>PKxC?95O0Qzg$I}^%{mzEy`-&kYTvIaKHhNE2wSwOc+`_#xrbj zrie19+5x$Md?iLz(XG9g$+ZN>*eI&1TW!*QOG(JNoxsOxkN*G=Fvch3OB%%*_nrpe z#c+j3Vb@5tNm)cs{{WBEd73{{0!){78J8-Q%pi}j%J}GmLvJE?o@SDa6}&*qK)2Rp znAsI%$qZ{IE(A4XR7)63XOucE=6}34jfIv{yGh)~WGoTI8!R&^LU2GvT7y?o$+&zI zQtE1+%eXCti^$8R`k6bA@-IEpVIUs&-6FPDX#IPKmX+`(h##LEH_k+3An5 zhGN;dRzp-3n7u;WKM<|TP3o?t1StyKdR#D4h+ImTJ;B-wkgW>c_L$b|N!x}hZ9i#$ zJ~}Bc}eMJAms@9$+=TzP0NFtfCSbtKXsedB)+4kDOZ6Hf z?1LBo03zlm=ore26BHC=!bGAs+!D)((FZyUUgDE#aHg*FQxwe02&G5Z1v`2*EMw}n zON+y%$k!HkGeR`Pky(XhlGk-HlpLO;V#h=o!=%OmLnlPO^xAxhE%owUz<9x0T@YC^ zabqHAr+1ga6cpVo)QzxILCY64^oTjT0vyQJiJO7hEM}lX3@yTlhLHwFM9D5FMGGOf zDX?%?8U~7uHZdDIpj-lZl>UJ>2bueqWtVbjZYIm_NXTlF~ zOiYAgF4q?-m8K?yxH#kZ&zB8&4+J)!Qd`+5cqG@^Ut%E%Nsj;`y+*A>@_e|yalDvy z7g~*aokXV*S5yHaz=irythmf*2APnk+-f>ojO?3Y8~mr%E(?`@cxV2GX&MWVP~7IO>KP1UXsEJcHx zdX3M_T84=ZnYBJ4)V+drE`(_AroNWRa)GIYMK8%R#1fQ+nPfK!5p(Pid@OG zT8w|x>{e=HT3ggCinnMV2DHV?fUZ`OtPEFjcj~R|&s6Xd`nz1K>kJqi%fM<)g-WPx zX&0Gw*75vER@~}qGfn;r(VpfGEnxou6b_CFX)rkof0-~ zGLxuYj7laO5FymT`ak&tFiUA3!&0?3iA&NK73q2j-Z*Z;ALYV^Llp z9_E5YbcckZ+(k7M-rYNy=QZ&*#g9o+AEwMGOu{L*kCOxeK%@ZR9m7ByH5?wRmz!m& zRiUj@zTyIE!4Oq7;DFu|2 zlpsM3uu=z*suz%>exQz`-vxQB%=w-PUnY!2G|D=c@?u#6>N%upCF03rEy2A+X1EEM ziqycBah%KGNA!bm4rRJb)l9w0=wLP#xT$uqh9zzfCE-o8xI=6R{*bBK(1PeHbr0jD z!ErrkPN#a@n|yJ*xrc1q=pMDEvPPvG}&b< zS(xDcC1R}uhhx!*jsF1T!9Dog%nPfES803+-+|Fu8Pa3tr-Ud3ycHRzv>_!>YJHt+^!?iPrw9YQUyAWj6w8RJ9K1sbE2k0 zpXix-^(y2&l@nk5A$CHFSgU22yfIUxH60QiNiRj=1~G=IBVii^(C&DH0g0HNN*zmG zN~IMaLO0bbz|1eA7HT*#FQJ(JM>>sWC&p*gIbS*|S_=LbWuT)nu2h*yKbuoIP!%kg z`6Ljg7EYX`sF$uEiJwsjENRsIa3N0R3{<{O$$h|&342gg)lkrSYB)mc*@{@on8U6B zxbYpk7QoV}VHgiAtQ#*RGH--a)mNChOjPv^JGWAx62hi9r$cZ|p241fS(;`sVPXMp zp}RJzud^k`idCR-nK~}f`7G3}l*aYJjHCh(*#U6gG0H6Jr6qoP;%xN~*$dlnuqxYf ztaj#Vq^B7-zT^99yLBGtWF`2eNw_(3_p;Z?v|(_zRiI@s=lp^;Rpbr^vk?uDTN8ik z3Td`~VwkOXVdlU=&xveg>vJgvt=!p>N?c zqpvG7J0En#Gs}OfE~hHY<4fertCHe`TDHj$T)?^A0ASVY9-=<+k27t}Sgr!ItX83^ zW&Z#Zt>iq-GX@b>CL2%W5Wa-yc+5ZeA)!mj6+f78P!OCF%UZm-cVCFgW z-aJ5D)S?jdkxJ3Bqa72J^n}gF+|xVER9FvTn=)XG3LFrP2t9Y=RYk5&;=5i6=K^+9 zu`vF^8F?Ndm5-vM)f-h}Unr445sczh?puac0;aA79CdSK9s#R>rJ3~)vw){lJ+TP1 zITc;YaBu8T+@!p`iBBG^s80-Za&IhFEE5i@f94XMZM2q+Xtv||L|sX8O!Ui8TGb-C zL^6cSlYuKr5IPfx72t|`myFqrVTV$Vr^vOuH<~e{9m|lniDt6OOvPw(2;;vZwIZRHs+Alo z9T6%!vvmZrnMgDRS%MQBE+t`9C_)r!qF#=z#Rj7NW>sZ6T+a_h%Nnev9X3U=rmCPU zivIvB@)H_|QMtU)WkR%*Wlx&9s5W5}SXD}jQ zmpx00m8g2S8pi!f)WgCqRmZLM!tNCXp->az+)sJcvW^PmOqmUY&U_avxWes)KVdQX z4K0q~RNwaI1c#|)mNy5XGQZ|qpnl8nMcGRBWn3|c-|nFq)Z&Uz?rKjcxVsGxkiLb=!~kyLh)mNkFeOT;ySkS91yljvi3oeF zI*fBo*(^;g8@Ou7$n2Wqq5A=y8h}5X;#KeZ%-@rVQM>#a6+t5cTz&x9T zDR43Z)iE-L2Bu0eSn3-B4-2m;U}1k`6d7a_ezwGH8?>}s z(W$u>Qw%wTmywJ*9mgI6_9mLTr&7O*pp5tuq4F6(%4ztWh(f&rVyk(FR(l_=FeoE3 zUDWJ!ehX+yWz9mu#sk<~?O+69OhU=c^|)!JYca)A^G#CC2kKRpuBPG(Pz}_jfF?E6 zT!Z*RjGuKXruJ$gsck%AncZ_3d|DL?*|rON8Dru7+cOc4*@Q~eSihl;Jd{V1OTfHB zt{WlB%F6!$FX4uB^8%*d%WvVQD^mQ|hxZ(Kn8w^|{5wZeUKY5Tj;o)fc$IwAwlLYx z+kWHRaHvCf9G7rWZ?yYVy|&3~+AI-QFVe#aiBtEsVW{lHsmXZC^-O^;@@{+G7>y2A zsR>TekM0i9IqtocQi{offyDfk`?C)}b3f|l58ew6K6Fo8r zzThj-7i&ZJyEYGy&^h>26& zDx`Q8;4%y6b5r#H0ATBUh;tP1tFe1!&B9Tq_;Ibe*!vkMpZ1zOYKssea8gXa{B_}9 z{M~b>BVWU}@ih|o5ppz%CNC#aYF*ie*{@b865nDmq zO#Fh5{{URBus_)97``k20QV1@m*LcEC#I4hO5b?y4#=CvK~rQduM9}>d@zGZ>QvS@op&-Br5X3V!=Wpd#964I#8~y`_BHtyxRYblC zP%nXm3zUd39_2B#p_q747*v*v%(IG~#}c%Z!vxaN(BT_|}3+QJR4DBxa#70}O8sCJbu zfZGg7FdXoAVIC2J4G8X1@$4dl0aZ^)5afg-y_}U^o^nKmIskV6e?&0v+0#w+NGL?u7w@V2@-R0pwEP; z8Zzrt$%5mXSI@ZUb_YzqG3-l3Yiv%vl?5O^lS1Vn_2WHRbF9rjen6SMEUBy`P8YJ2 z&BGx=TKr0s6Yw5cwj-#OgN|^%484A%D0?E7UKZ+kV2UE4E+V2U`0kSLibI%~mX!u2 zN|;OKar`bjmr|SyOX9*fa5#%C886MWtTtrS!Kq17h4mU*S%DCO7#EkvsM!&_9ZR%E zgm#(ody}ZPl`lOIVQew=p*fwcNdr6ixC|RaK)X6>STM4&P z*u20M$;)1MD%JGDVg&9bg(nPDSB@OrTdwAtg4t@I>pAR1gEH!=(=(8*w=~^(!I-Wu zE?-L7%&|6c@Qd7|JY}X04&}6u&B{{Q@R-jl>`j>yt19h@-!lu;pt*L>i53vlMX-_( zw+0OKDtkNz;DZx&H1owoKN%uto+<}77xc#ZsrEvWA+M zGi9e-N57h~Fju2+p3RY=hW3DAN;d_zXy}1x$6%?K1GQ;`?VWi{9nT$bGdvz45b~~F zco-sT#A-+No!~~G9+<#=VrLp1#6PB*5jArMU=qPDuzpQu@A1PCxR-F@Wq>&uXiy6J zxt9}`Tg2IaR+Yk6hNhH*AcCMet5H2u*#MBMm}>OU__h=prV4a$7MXmIP%zPfb5iDv zJ0TTb`%7+uiOxUlf!quGD^hC`mD&i)J~IK~ic~pf;9`t#0+cWx(o!;qCvu9XK}6|O zv(&YbyV&EU4lW2X`7zS!Hz^pw&<~L>f7&T>{f8R}jNj}pEZ!Ssg)a!Y%G&o@O&TV4AvwmtD&m(HvPUOwn}1 zs#)P7pf*QP{j|Ue`q3>>(KJ;{MPL-NP&fya#YKDji*aVd#y= z)xlqrshZ_(V%bbwU-Ra5WG^|5%(e#?+zp!VdV7!P*eI$9O^?t_Lv-9;oHNC zKV=^xa&Q)iZo>Q!x`nvzA?<+0Ucxt@d4^hEgL4flU`)^#48%`EEeo8okt^K2gpObC zPa}avXDNv-8jcsuYy-5}KJ+B9gZPgVcwCBmmHj2cKT`6&jKf&RS~-9N19JJN3#}+! zfHFmDt98`Vt7zOh$|JVmG>Vka>M>XjrEf`~O2oD1Ja7RogO?JJ6&J~DdElg^q@<*G z{K8ii7AA4T339RVEtbKHh_xvxDFH5D8}PL=%$zJHqITdLNapW(595 z8(Wl0PR)@HD^O@^K(dZP-Px(OpKzX__YktpP}9E-6>j0||K~gsJu{F(#fTq%Nij zACONK2rj-OxArkBuIouuQNr1X0U9H7OG~XQ$_>RwGN9q8HNEXUCZI?;^(tl9gcgd$ z`vWu>mY^>DBNj+jW`3{R6#a1wQWW~*FZ)iQ_dW_{qC)MEenYP%KkXGJ#G1j2=37VX zyl~bG+T*tW0Ky|jI+g@^mi=c4bRHA5N%<2_DY^a1gHZ0bo0f@Tqe+}wW}+5B!8UoS zp{;Ivl|GBOLK!#EH9{gt@l7*R?MK}%o^DXMuxGtP#AzR5ukMt9dVaea2uMjw?e=!LSg3P*p{v_ z>N=N5s`h%8ZD9)_Zc_|`7M>z1y+dTCSYlTi8wp%Th%VNL5 zMZ~rwElc|oQuD~A@nNVeTypTqDx4|6a4c~a_`#JZ2$KvLUM0ffH`JZEaEaWQ9U}!< zV*WLE1Xr7Vfnu(a2^1{*DV07;Xt|rz$>U&5*4T-g4r&uR%2cP-J76y7brsIv_?IFT zXee54I`lG2gK4X3W1uWG6A-`cFH!#hx?-NLol2(FhUw`fsW&<5BO9hi+JfcxzxjN2yjZhHG#e z#lV&9HGM@=v2o6#seiyQLTeoO1;wh<{G=y z2ykzR8v-tp#P$ThN=xl7SQ|b;uOP4LTRF<}J^2Lrzi&mrqsdyHMq z86ayxdPURohx#A=hTq8a8-Y?44#p--1^~RSSAvHFjs$GqO*c{)^mhXy-@zJ3EJ`&$ z@}N+nekEN;ok34nag}@-^<@_(bt8<~UK#3Ek#PH!qv|+D)e@-=U9m>e8Jg@v{iJ(; zEDf=B5uMFK3EJ)MU1tDgBBb(mxwhW*QDxD(ao{fkhj zrkG+S!G^g+(G9#A-jjOx|KV}OL@4EUt!CNx!q+%!hjK$)h!RfjA$j^JX)EexgJ~96QlVVVn5Fvgr{`u5V*K1#s(xC)0Vee?u{g1Gy z>)^w&e(=~GN8}A;e9Dcsr*(${u%`b2`z^`jxw0KVjxVI70gjV5-JavKtyh(;s26)o z!{)O!RxDH4Tai(PPllVS4m&Gp8%Z*F8tUaV)V5xM%cX2LSv+c^*iES;^#NAAxxaA}(B5iC| z`5uaDteP=zvd2gk5|FNKrZ&61tYP|xGRAT-vMHOfg0K#KN-}j3j%SO4$)Z>ji`2JD zQ=r)Y0Fd9whpOLW70tT6%Cuqu)GmVC+FkLROa;NU3zX0Mm>jl}`uYWf*kQWg)Vk`f zu?DlBvBjyH-~}Aq_fn+UPXwG&gd(Nb>f)u9vdped#bVPyF+)8%O|=S$6%0}Wpuk5B z;Cqy28}gR+xAj2k$Aw*|Pm=r$-;kFO_fcY+;trYW;aH?S5T=o5y~c&7DTBW3K;q?M zraX?bebjG&SH(bl5MTbLqC5FBK)XtPT17`rt2vpznQjS)aVfaEq^o6={aFKRQ*`?j zlv&vk{a4k>1hf3bu&7=%@N||sV(t&}>0jdv1%p!(7aE2w^CP_!hyh z{y+;{6;I4~;Ncv(8-F0JinudBgbPqE5UC4C0=21R{{V5N{yK<6faU_Er^#{%WGSu7 z8t}(!Ke$GVrr@yVkvUN@i{cmb6)U(?YwWp_l`9nF=_MR(QC_Ia>}O=(kQJsQ*ksF5 z0je~4G18~ZGVIq1DP}*ojYGVj6aEKcFW5%Ve=ZJ=xb9U@`hp0b+G(%4CbS$Wg$U-E zb85h>RHyvXq16hg?xVR;{9YkwdWxJ3re%qk15&V;{_@(?!i7qR8*%>t`EPiQWS^9Q zDXQEgsSP(~ZcWn~qn-^+4~^^W4Ns<{5Ix*O%bYia-y8%Pp6G2GQ>4@<>xe0lQ&>rP z23F{fnbu+0%o$==MzmnuI^5c381h}FVVPY4ZBLUUsA2ms5(WH1AidGc0``um1>wor zPjCC&=}RTzZ5hX@IA77^z(l|%F|A)x%E_nMa2JMApVXJWz8A4_aiFTY!1>A6_ zQQW3!DRN|EG-fgGGWf)+8>lndV6;C}k0tU`-*r*@p26HBs#-$0&9K z+fn?z;FMbZA~w8~-K2~d;kBZ)lxAuPW>{kx-UQIvh_+4LhsZ&&p(P4 zxt{3kZ5^vI#Ow!f=a9k|{?5_$15HZ)=9JqzsogCnjW03cedVI+><82${VUbr6mI-Q zrDK>K>Qaw##WwtoE^J}USnAxrkxCI$RCiEeg+hMK%*|cWgy?-r`VOU7dlaf5z&2EO z09SLEPZXyun9t5hT${vZk<3Eef7ky2*kG&E+(oSdBnF_+jDU~w4XUG{mB&*50BTXI zsYi3D+fjgY_p-=f7+k>?+X>fG8A6($aHVDQC^Yu&erKs!FGe4^vrF4TU*vELX)z6E z?gt@67lNK3q}eO#B1f*JIu6*b%qA)oQ1&V_cEMz=3+~nx#GOj3P0BS|aO6bBW%x4@ zvB~OZE%d%hu|uryo7rEK>~2)D{)pNQzp-btnU@n#I=IyC0yu$1gj0EGU%=`c;f=8j za2uLMfBXS&_=UVUa9MfaR9SqPVAM`G9^&vSNpn3 z0;Zk8U`M<6ghQ+U0PMa;*^W5Zs3XUs-w^6-N@ZESyhTY`5q4py(A5~?26h`JR}(h{ zOI@O7SP;h>aa)&S<1g6){fL)4B)NX&g|*eC8KMo(kjj;^K@`-WiF~)%m`SEuc!DG2 z2aKlGvzHT2%2N(OTktSmO;$21#VZgudGfl~$- z2t|7@lLnCdp#|v$b~hTazy87|vtkV~W(9p+H7Xv~mLP7?$Sk1F7ds$D37cXMO4kEX zbYai?kJw%eBq6i;Eq5Hy{?#TYYRUblfLFdjG(Mu)U zc1=eIi!W=A&+!}nCeY!$>;C|$*DbixJBqpX=WbA7S^2}cRq`#tt{b^@pR|=YUXvL{ z;)#I#iu!41htAe7wNRe&kjU9CXh2?J7g9UrsJCpPQv658gLl-TU+AU=(brS@84N{k zxnVBXX&czez^tGU@=6DWmpgEJ*SXvy$VindgCdJ;8i1#Cpl&W#q+%~* z*^HgS1%Za+&QO-Hm=>xfoFD43)pTkF?iB(Db0eY|Cg3DLaL6>fmnF=^B_&U^y;ZOh z8F;0!Wb0!{WvQA^bELLAcD>B|tmf_mo9VShro}d;nde5B*QUThU>ct1u#`1y)@W7V zZO)H%aToM7)(N=OF78p9lC#S9}HXiGY^mn_-tH-`~|X?F|aP?yB+`{=7J6Z+*h$OJGs`Otm&#xyq^uV{v(m1btwdz~K#C1O3BI zb;h_L3`u3_ zup*B`WL;_MHUtVP6_ezZy6V27DdNn#tW2k~FqUBs4^X?SpR&&zj2}^}tkki#Ku9Au z9TN0dl-BcV=KUu z^e*9TEKqT1^$@#?7uv7LK?1l@4xIOtD)R0eU$4pccA|>e0PwUSa^$~>ffW}MAKXsg zk8=yfkOVsI+}R02fRjSqpg2YBm#Tt~2*8+Ku`37CC*HU2R^dgLqGbzmrP@E~#Lo)p zZWTZjUr}G8!8+#${edYChZ5O@LL;r3gh}ox52VJMmmQssrK$IaE3OGkt_hHg9-@;N2aFVkwU!fUm}QvPs7>)u>rjPe zY1(d62ht|jp{bl0?h)5&^_Dmn3FH-s17!&!QZ)z`>P_xNOZysyl@_&cv^J;w!GX^qWt@S)S>Qji9zDyu!7Lx@kn{ zM6-o=1jkXNAo~e(`ckRS^`jb1#J>yC>}O$7Ruka~bGa@4lP%LQhjD%NAfu@!TQfRl4AR+BB& zOuoxdgWLsIEUnuZxY)l+?pu5MmNN;1l^T!e)ytKB7~spO^6PE~`}K0!YK87?e8O>C zllL7DVHv5iGY}e?8<;hI(zC=;SYl8T<3x3+s|YMi>MXgpD?h>;{{ZM-FFY2 zIHkoqo6DCH#5i2R!Wc7#7I-c11;>0)!MXJp3#Zw1^4I?WVd`B8fR)suG6h5r=An${ z*`B=Q49yV4nTv8>*E#@TQ~gK*gBu27EVUgsah4h?H|+7o1w*YJbHC~Uk46UO%R@GY z;%FE=mNEEc~X)={6gu(Ho_KKQavWQ$i(Hp83ic>Jy`yMwH zWlOVVxKy=92+uY*5h2Q~C+Gq$TC^$QC{w9BRMp4$bZ6vst#dpp{Zgy2CcWgp?=>oq zxv`ME#K3FYmv}vcYuQS`#br+6NDIN|lvCJ-Vwk&nm30CNSqL7IxaEUO(KGJmbquci zf~QM^*jmiPhxZGBeU-yPSuoTA_I>GXFBNr$w954^Aiv_E#wT(Lrox_-&X&DaI~Tyi%#im8M4RwL_?vx!x#?XmtFy%+Yn{~tXJ_4$nF}gDi&3Cm&s-Rb8|38lzNF;^X$vC z4#W!adc$)$KOtgEsL~w4jVv~bbt_c%nEwE*S90|Z7VR-I&^u~b^6xQ@_js1m29D)v zjf!S+(-|c@MsX#tCIi^|_*m)bR!?Q3ER}^g~j%m}D zk=G8U-^VrlP5%J$HsREF!QU-se7A8|2GXEIq^hB5GEhO{sI?~8-}N2yDB=lD4}K6qzYtneKx$QgP(W!!0-J&8MFp7%OK9*KmZwHxXJ0t~0Hgl^v9zTo zLSZ7xqcrXrQ5E~e#QI3-WJKQ@@fN9p!-kl>e#NY6PV>A?u?z=fc>SGL#v*=F=;(}@ z+?M0~OP?HqlF?bYN8Vf%XIqFNzex-j=!QsAAuC$dFU&#%%oSq|~N1kyaMcBbTk zVk_!*ONV+T-!dmFj0ag(X0-Q>=G$c<<5a1Qzv<4g_FY>L zr%@T@s*l`)voMvy8VgJ6QxQJPw*djb%x@|)cOHgpVilY?5K=+7#C~o5R5BoEGa9^L zgG);RFp9%248%+To$=P45!VW3!$@)({s8_$+@dZ200`1y$Th`z7MO5kTwbTrVGS!r zb|2L2nIdVr{wtDm$;p`)iCe#hTPpUA8yor|N)M=QAD9N2CRwY^OxwCgsdVifxEV~# zcihe2jJvs28My+Z8}L%}E(l;Y0px3;A?_Mx(`acjw?EkeQ&IHK9TVQw3uS`?PBE`EvSE~M}%jflme-?GNS$xvjwbP z{{V5oS%0QYB@EqMu}RrU0HWYMkgT(7**~*mkNZFSz|#>ACN_e$Vr!I0(i_Kln3!At z03uh}ggKQ%vWfnv>Q*AS1hdFu;g^_+_9!(QlH20y3do#A2HKT$RgvGRXJE#)V2(S> z3NEz_y)SW`DNG=Pd<@i#79xqriac9#|-id?wh#95avGo9SaJ4?A3;j507#mSx1NpVAyaIV5y z>^Qk`ESMSI>R$paf%^fjwQ{lBq$r{I!AW6v)FkH8huh%|PWoahT+d@h=dz8Ft@~{Ru~2Ho2U-cOQY=3pwVXQsIj(!e4nb1 zEb&h2pX|Hq)~9iKe_Vf|{{Y$MSj8g$0Q`~(kaxv4Ns;>>V1ow@dABCG+Pz1yTqFJ% zwK}PEJm|)bIEMgtT$f z3r+}C#O9y`{lX2^Mj^m?!otpm+$UJv#a)u&$f}E~7aox40MkG$zbewQ_(zYBh1mzA zhCnIT6NS97PNUimK7EI*~C|(btt1I5!Vi-rPL$S7=pMfY+hE_jW9i>6Tt#~ zb=UO`LyeCjQIebQhR0{{KFbc#oke!exOXUR!**oHrW=*YCO+42m8u*SMgttr^ zA|Go3!%n4C)BH0Ax>gm7k(_ZY(xvV#`x6MSWfCspcO$I9Vp%)*(oLkrcQe-kK1f}l z*B;^3rJ0OxCNJ<&-D(z6kA_f@F)0Kap6g;Jq~%LY&o z8!s@WxJu%IQ71`p*_h$TBX);Ulw>2RxH^WrzvQA{Ai|4ZkFi3D#*JpL%b2_^F6qIf zR>VUw7#Ma5Y@H^FD~<(4>M^9-F-+P20EqR21xrE4+%R<08bB9lAOSyI>F}1t%q-gV z+z*=K;^o8kVgCRmfwp~>(b;@`HDKjh(Q%R!U8WTx7W*R}yGkqSH|Q@J`%|l6^CFvT zJ{iF@a+=vOeIbcIww8=ymOvrOv;D-5yuL0}?!sg7RgA5^914->#KJj^FovD-f248R zeR?8PKqC*47pCDA_qWJ~6prDo(Q?wNzOd9carHO<024p6 zvlsUkR~h(6P;R<>7kRrGnwnLyf^k9&yG#E7hj2q25lnS(RFC;09%ZIhM+WLKVZ^(r z8$<4B;X`FRn9*5M?eX?oP&K}%LKyrdWYHdKZZaD9EIlI;+L<0fEB$;V6e^HHdVLt< zZ7C1P#2l+sme3ftxUA{OBAuZ+f+h94VgvS=0Z0`YLR%1>(ioEh1#aTPsMvd-i3Fxu zW57#SxPp;X+p;3BnVMr}T}KdbO1PDNl@#WJ(L7&#N*QH=c1!~Kt^pRlZW#*(#@6Bz#@+IC$A3*8Obs1AVn97RA}bMpv5lo!GVEro z(7=X3Wb{^cSUX1W@(X$(lj8MU_I^>HRA#RdWOHZjF)DJgL1HVM@eA?xaOuF;3+|< z0+ns{UG!PjL0YZ5Zfyw!SCLz^G`{jzQ*2Wa#^7m}%zw1Wz%g-Bjl=Zi5MA5^PqQ9e zQXa+Ygdr%e`i+;^Mb+Y_)A*Tw1VtOR9uMoONS1|k$Dswp{!8;uXu|Seb|R>Tn~x-= zim)@n^tz}C-tJIoRft|m;gsTTWTL41FlAJ!RwApFIR=QhPWU-Mu0wyzPvO@cV$@d_ zsSt&DhkR^Gu12c%V}D}7FR6%`O1R*_rW{VCO@Uc}mLm{?tq$?i_Fx@K+GlWpPyD$s z#+9FOOGi#Aj-803veBqQgNM0_YivM2YnIwnzUy3e<(VZv+)tDN8`B#O$$E^NK|S`J zP25{xkbzKj2=-$w5!zoe)6FDOjo}Mi#YLN?uOe|#w1WWON_WD#{rFj(mw{seZQM*u z1RwSgOYa;*xu6=+SK%F>)PnMcRz(y>o)WCq%+9jw@t@LVQy#1crX59p-^1IjGPdMS zhzf6BNR8J~qE(A#e3Ze4x`45>C_M0BpB6>ULm(IX!+-w(a|z7MvXEg6lTK@F*8nT= z;!dekXZ5fK)WmkngFAoJ%*AWZ#lT+l{{a2)Wi;}pP@OPdn8fA8r~E*g;_)y!3Ga-0 zp2FsZ^EDeUoSr-yrN{Ek&G>i!0LiED>yErSaOJ6j_z|Zj#}2X5X#OmJz^jZ+R5pZ@j84sc(iy4&; z%&;3g%-*s3BQOl*xm4|)kII>n_26x-)B7e*ta#B)Rytfvv=?pkgtg>MMs*^2?~DJ(!m7_vBDP1vCEuPXa3jZsD|Fosvdnl&^I%?${{O z5dQ#!W`JP55O;VXe-50-^O8-$zsD-s*?Whg*jtBm-Hb3Ic6+LQR2MScFt`&l`NLCi zi63SN!WfPu?42I75BgL(_K1qp)DAf|nU;buC_zC5`OPFoDAEB&q61mJT_y91rWwCn zHKV`yM=^?-Dc@4+G@9oj(=6e!!#Z;NaBu$rtZDo@o6RR*z>jD!~cp<8&QTBu`i_|0FjJ?xP;iv8aeP*+0x*@K_ zFa^RbazRVQ!o`+m)&+A5;uYjAFEdcZ)-Y2h)jN#k)f95phS4p@C%E{oX2S<2PJFSM zz6PGij!u+rQ9LiKOG>kCrWt$UCTgc~)UNWg!c-GKVN}adOsTk>sbkFRuFzWW`z|(a z3t3rFR;{dK2JurXKld+9UZYD#VTNJf?-rx7w-c;8AoUTI=3+H9t_H$TBo*2nI4^LF zZ0=K!`AOcfmPZ=K76ul@}`g3&TfBG)o+L|j(3Z-Gx=N10pR$Q`$>8-2DQl(xRJ{k21z$0h$+tbjmeq^LeUlxrQQ{%` zCCH*LOp`8uCIqlD#z72X6Aw%#u*x^z7i_*`3x&!50Ekgd7vhzZp!*(Nj5^E~Dy+F; zV*A|&vehrR4A$S0D>x;h(UkHz#OQ$WVH1&EJ* zO(s%cc|MXAf8uP2_F@Iu@(=@F=5+QizQ9Ac2qw9VSrr}3m!iyT@bYK4TN47HZe2<& zz^?E`w8QOgTn_Unst^&m{vj6>vRMts!QcM?C8sRXZ8YFB!o*unVx*U@caGR7-a6rL zlIUI{#-PdEqnIIL42(#&3yHBPk(D!_v}Sdgjs#h__jWL|zhWE|!dW8*wvr;19Y%{I zsPI$Ry3fUoWv8*S3hq@Hb;Z~lC>rcTg6%RiVauhxz;5x;Ze3gTA zRI@XC2CvjieFz-iuacf+xDta1=$A7|p+C7eP<$g}xrK{R_U14vnubkoTm~0t;r2Qrpn*05fX?8*jE>7uf@nbYv8ZBZHO3RzLGdh|mDc+{i}C?5Q*o39 z=Zrz3J<)(Y3zZ#kWy#wYsHAi3d3Aq;LiB5ev(&h>EMh{@F@$a(@a1Sl7)M&n^ z(tbS)Glx?0BJ%dq951u87NRMWvFg`QFTj1^j}!r`T*8sT^HF#nIC|aS9^;l-1q&<* zH&tu|Sy;M{%2){cqi9j9QO?yp$2wI}Q4WvY#DZhtlveb0m`L{b6Y_U0?t|I7RYsG! z;)T!BF{wa95H*=*BVEf97=y06#1X!-*7l8B>&#a0uf#G|w=PWv%}wi!V$2&On}}ez zb#5P!**b-1h%%*W0l9LLqQgmeW<88-xPwHx_Y+I0(1NcmXtNeM7MVjI!YxaG5w2Qt zxl~(@W9u52k=lbAy!96-dAO#SQxGi7ZdWKaA!u%9H*)&T^)JrlnW&aEQ%EXZXsVSp z3LOUq8vg+03?wHE9!|GL;cI4FBKjS|pMt`M7&?L6NNeziwtlr6C=bXV36F+-hs64g zD&Y*9%8cQ-KEOI`+>EYjUG00_pa#u7m>odc6a*G|NEYl%RzY^$R>w(bS1STK7464sg|{-3 z_0A>@lNAAqTE-Ujk;U8%3D#jTD6qjd4KwVxr*7i$%v)4zND8&Y3hXwC>aZ-kK8hmV z9tl8sMFOjV+%Szn?88Ax`iInU_HUgx-eV{(*^JV%3dW0;FW6UfMi14f>R2|VpV)ZI zD`nXu!53wyvE0CRL0di=f6TLRHKmNb3I71&0>KVYe!?|nkM>MKkZ~Jl{mWNri5mz~ z1X58dzG4Ctl^6WLBe<=^pp=0r6u3~2;JHbEz|1wua=Di!k-grcq3e&Wy)q!@fk<&0k~nA%Zdd{JHpo(T1x)_DEdYILMI3;^)vGyg%HuF zJpS-S(?fnws;a{ifz%cIMink?F&2Sux%d%=XMRJDCvfp})4&uXPU1M?{{Rr6ACt=F zxzPu*f0&a`dN^MZ?7UW`=-p~6M!oWms{a5Y_!i}5n+WwTWLnqkUokEJ0A(TN60>y$ zhrAq>ehhm6g|3V7`NEx%y2SnZPk=Kj9e;?6^0=+=LNvfg2G=SKad{&n*zBKKtk;E4 z(<$ehoJOLr{xJ=I@H+nhJd2fa@amXTpI7g0qTj&$K% z>w_&va~W42aBcyK^tw#q{v~dV2={SSZMm6gJ5e$PMi-==-jQifl>Y#vrL;EXfgX|e zGj*MN9a6w1vuK3zHwiO(Nu%=q;Ib8Zq}0Rv(R+y56R7tpqTUi%>KQ%$A7mSTL!SWx ztF&Tzhv{eeC}!p-`QwOPV1ZtV`3?hR95I3mmOx3c|7(tL~@=6ID0s&AX1}-cQ{{Zq1zkqSVu13s( zIRmJcV2fNDH7u?(wy9iTj7oQYBcXqio8C$9^gts=?Q})$i0!8mK6z@?FVtb zVeY1PF}50{H5)`^xX(qQ9%Wgz9d=0WQ%KdMZ6B!9olLN1f7nhE&Jzlh{gzb+$id^` zE3Mnu@|MTaM~qHv{-ViVfpWc>)FOZ=isw>hW?i9~bS?|`G8sT!uM!O{m#kUr61qNO zUhtJaQu{)moCOfo>6nV@r(;ppSzW_g?!v7V-^k7T0LUG2CQ>s~ZUb_taJMCx;c(2ln!uWmiAi)rDkKN?&d7=wbf47z;Sg2oVaV=g zh@D1=4`t8Dqck(fcYEV+$eH|6W~awE;uz+$R|P`934lGo=Z>x*>xuUj?1tau zM!)zSa@+Y76E6+kXZSnjY)M$GoOO$fMaL!Oj<1t8J-FPkdZJ&3B1K+QvL+4$4M%+t zBRkB`exiZYV5PWa84i(%a7+;g5MIhenzd?H!g9LYl1=8X+#OAXcR{LW3Y|d24LrK zW4e{)!I*A%L#vfFfKcLGzp7qLmgCsEf>+s@5or?4U1(s+RvMI>Sq8JLzv~?&?aB=rBEHx}2v-BZIOr6|i=#R1pShxXLA0SSSdvDkl#tBfgZsrS!W*?$Z zS8KUY<@+cheZr!pi3%PePjFh?5DAWr3lc8ZjuHd9gdxt*bJ&V({!C%H$ZY{sL$&sKbdA0lhE zLgz&Q7!)l~!705eI(tmlGcH(FOPE*Laz9x`y~Z^VKs}|v>}`k1T=x|V{li~!ue+;5 zxC*%105n`$FAmdDyY4w*0|k1EWVVaSFq_0|L=$ri7d}g}gsA8tv*vsWm~J+nAe5uF zVnMVkc;J;q)vi1Fq z_j9PF9nMc3R<}RAXZS%esbdmhT}72=f~t`PIFzWwX{!S%8#HET_L(`O$yH;rR&ODg zBd!Rt7m;UA$#tc`O0_=IxRiL)Ty0`Y>Pwr9C3{!I(147G?D2eKF34xRR<}EM(FT77 zwA3Pi5Y=BpDB!6Je_cdTm-Agsdw3%)mlj@k7WWmwg^clThUx5>5NIz@6}>5fr3TmJ zGzhUV42-|=6m1h18~&CiUU%Dkn8gd!4dnjih;tOGy1RvqZB#I-tSLVs7hE-H+T??b zJt{v`Kg=yLW~>tmoCkVO{CUY>Ld)_IvV2d@a;60z8NWGSkwFqWW(#uZ5Qcjt>+%v} zUHKl|Tf)=GH%j6;e?;|h?2(?Ko(Kv`4P2}JNq~B&!qCSnI+upxK2Bk`vKnsrPM0pe z%h#hs0Eg_O?tGN42tEztg_98m&N+r?!H&H5S*|`8Z}aE>0Epf{$SM!u4LBN_an=X#<24@j7{tp6wxjg7-#HlzjJvFZte-!5SQqU-dmW4qnZl1 zC)wO~%}9d{Qve!Vd)-=nl)_e&#_<0DX-9DuX}Fd0G)DQA>7%$i2%-%NGDBWPigh%< zxW*t3CY`7kUY$qmytCW7nAUN$F$YMlP?+lzdK3hKpFLb;qPQigaCI1_W0_`;hjNNf zX5k#)Z&Ldejwh~uN4mC5i^6C}ktM&`MRhUNlwBlBmBn8ZsIMip*hd*uw43>GLNDwl zz?v`A{{RnTW>@L>aibMzKzW31+57(h`kCHv-20x?r>9Iy086+30Oq-9{FGK?WI8TW z8_F62_kvGp7DcS|{F)}Z_fmsgR$kj&Lto@XU}{=(T(R0js^l!k`eg3#tgRg&dEN?( z1ww|#U2mLG5Nymu{{SvdEt9|VqyGTSI^%iQ^9{JFS<6Yc7YR&Q9_CN$63XZ0zDDQB zq&`Tkj)_AinJrTT;Q{NVBam=500(T^rIkI?GnyB^9jk#V6IE=xo~7@ipw!-BM&|KR zaI9`szVf23hlevW88d2AMGXvaxO;(paB7twlGSWsPJJQ)>Lw8z69rbr3um|UoCL5O^U-CY|7;XAg5L;D8Ld64JA%y&J8iNIrw)T4(pr_b_ z+3t7*(K3LiH_jS;ilz;kw7~nGB~-VDp}E60kwW;H#deMvvqYmbL##4c zBxsJwdo<(=cnm}Ng8a9gaxKbuoz1w~9FB;aiiun9Om;4&j1;n6xrLJbuzc=o9aO^W z2;h5wGjWYlr5$5~s-G)jvne04l+zEhB3o4GhlY{to)P3Z+cQzjg+_=iAt*p=RJ0lp z?f1;z7R9O5YRtwoieW^dH9sX2IP8Hs^tLHk@NP7nS6#BuR-!N$a-mAHKIU_+4dW@> z{Y@+h073r%_7V{>*h@sQlCClSfy`BIpJlLjyT)DUqq%)kqo_FaDA7G&gDd;kZXJyF zjD@t1Wppz?w900xSpvKAlsbdh{?mEX52B8x*#6cLWitnOyxmhLGroRYa`+{CGh zL58eP`Iy@C5%2;dt6ermK+rk?HZUXMk8?C3mSQ#SxYd^xq{>zBvTZ73EA1O2$yEjR z+RoizpdDINcp8{JEc%C1g29ey+$KnHR6=r@%dx_tV2U@IOQ<6v;Mej**PY1fE*?cT znwiZ)olG#10vic{=y5Hg;FR4ZmOoJTN9dc95E$T$g=N%J1u+%U1cJ$$m@7EFO9DQi z`i6_Xu`w5Lf@SgZ53?&5DNdrQaEL10O!P&l?l00+)X%Vmke8Vu41r1xuC*H@hhZrx z*|^&w%t4QeMMkPIsGp?0P|=-^B%`6)J74^c0GI}EEs~r}f~>0(4Afz5+|M_Y6Y`UE z4b*)x8I@3(@5$F_5x*8yxT*bngvuse%7N^9h`tR}Jixk|@HGO^)L2%f>VKqE3U~qO zsCdd^tt?|NhoVq);5&u0^-`@MYFwo1x!&PMkO%=c@i8VgPLNqv>%`tm2%}&87cScq zwqrC$d>!R!-AWd>iSq*z#fl_Q8mOzgQO?z{1-u+YU7MFbu3h7)aus%r?|Dsg@lskz zpU~icnwA69*)&RwyyJXR#V0~(H~up1!LR;HbN>K=9XL9PZw8~ew5bzBx!MSHsea0c zV>FqL$U?&4j0dw}z7C03`7q@j)HM4Lyc38Nh_ZN>EOyD3brq_ZHuv6886lhC-SGlC zfn%$HAzbDv>M@079{oabN4NN4z#S!9D`6|2aoJ(Q^g=E$?2 z88|~JUiX+I{{ZUASM?a#)<|&`&Hm?;%7fA}k#G=pKxW*-A>s_%z5}(&n~I}ccINTX zQ)#ybzk;c6Db%#oiBZq-H|jn zpxFU#3T}7f#1^!LL#V3R(qtat^K&_keM+Pr`UBZ;6bw6<1_(RDiJ7?h*n1Vh+8YEa z5dM>3#BJp5?TkF2g{mJWNp7?Hc9Bb|b1nvL)OWUoVTE@J1`3Gaztk9yCq$c!;o}9* zhKW!)7DGPPoq)LR30vg3=#h+P>cmhcd%2jSq9<*87^oDJacA|Kj((0@L}c`8Sq5FZ zn$CS?!DCp|X@MI$`h<3lIJFz2L$h%gymc(c4VXutr9lx*e&b0ST@s^a9wFt9p;bj}l_P7z_8d{H%8VHi&vVCc6f%?%Xz?pt1kiN@6agJ(3%j82#n}{+ zhGAXm0#1_H{{XWh3i$6HQ)`CHn@zYi`~}LH%m|iCabikv>QjKWEka|dgDJzb$cCY`Hw2mW z7|`PZ+D5^mc_aS-Whl<~2yCqcs_j`0z`(nK`i_UPH(`3(;%M9yl@Yx733-k=N4_@# zOb7RgtlTuao-rg0aJ@!!Ha{81zXe{-KwU28jO&#;dH?a2ubpxkU?ut z@)bGph|uu^Y3ht7P23R|m@u?U8wR1P81@`D8M|&*9#U$En-g!zecY*EZ~jXOR#ajx zoTKoGLv|zvjkvM)dQy4> zOcpB*%h8+g(S{AJ68eO#UPZTt0BXal_lh`dmmZTSG+q@`r~FRSNvAh%4SzFywEhQQ z3lUJ+;+wX4a)9d8jQ|QC*e4y z#f}6t;2C7;MS{OvMRW}4>xY|(U|ds&^+Fo4buZ2mhDwubp=wG*wkoNj!g&#sE3jbE z2IX}$3vEQ7_7Kg?Zf|i=D#YSFTui&p2<=;_JaowIj;9oh=hWQMlz+XK<=X#?(|$4a2VAcve@-Irkz1l zC`Q^VOu(A*9>5i4DkHgrJj~Bwk_3i>dn#0_Gp5;)xFW^X$59T%vNq8YLV-pud5(}v zb{7c$09m9CM5!iwiz2K#heek%)_2G>1=d+s4&tawzU5y?14z+hfs8TYxhcH518~mM zehqV)+;;N7QmvWVykvOPzFn+9vC^LDu zQ)Oef6i}CCVTpNvsb}PS&|DOOUW?Siv< zAibl{$bgttQ~N?Rv|BYIWfC|Nn9OD668I@z-b}=3+_FS5TPL3h56D2{{sDqjGiHeJ zJYgvF09ZbdbkJ2of~dMYLC?j;@~X41>>OCA!89A2>=FPEWw4ecIIPY#L+O-!u0>ojMOmfRQ*H&vE-ogI1FhV)31En#0Rw^Tttu-Aw;TmLV^dWqs|MKa7=f#}+eR|f zsDK-&dgqc~;sXw4rS&?Aa#McH)475((~>3446lMat~?I=lpadBK&K;~?eJpmM$aO6V8);Jv{GDSO7#=3P zh5rC?2!>N+vPBKtRt8#yyP1Aj2_2oxcxE%^TO7nQw79mdk)TrgT?e)Ke^e; z2EsO*r+9z<(!kU=HyC#sD^0Lg%G?bm<6qit%UAyZ?w|N@jP^;C*dCHQ@xyn((jBkJ znqsJqCn~>}DQzVMJ0^?;_Z;G@#?#!j%{h1M-Wny6tp0MOY?uE4d757z7R5;QG6x6# z=xyO5A*fd#iNEj;8_v8Nay8D3-=>^vcY`;Om`u*J>ZAqr^R)K>DZ)Q!K{m{V9rtBP495Jd_q`ltZ2y$su`*MeK@(Dk9hR z17ZsP!Z;q$!mKQXIbkU zfoPc!4pb(o>S;J%RPCuN^DAQUP8@|8m?>Ii^yqgk<7h@SvopkrFBzI|Q}4`Fqh|~M z06a9kjAv2bCH)Hz;}g1Ac6V_D@?Fd{48n#T_-*{iH^|rX=?(Fu)0;V~nPsDgEn%lS zxwe1mXK-?x@ek<5qLroi4z&w8`Jb6;xNR0RnW0s{{NYatkhINTEN$GG;klu8iE7td~zkf`~0J@rbNSSRHn6Is4({hG5%}V?s z`uc>t)?gKx-*VW=+J|LLCuz`{r*kn?Kf=y}0^~Y~f@P-A5P5$l}zet$BDV1EbvbQBH%mvu_KXP2l33vU2_Dhok>;c#+h-^~s z77m1#QNnJp_6-s5#D3yi%4LePcVSR3T7dyo%yvU=xu2JEgY2}Ltp5OZRlGwCI(4|D zHy6(-3Gl2pY zq+ljHMiodJZa5SzlVo&4xDF4nMQAPpQPT2;frwylG-FxCSMD=ifoWM&bRMITwWN%L zI`sBX^$kO;Xo^Zryx~v%5&N<^jD3kRMH9J*EyEgs@$xmcG*UP<4Kj>7?#iu z@EDbATpujF`v5*HJ4Xwn4@l+M-VGUDjvz!E!VU=9dxC$u{{Ufo&;I~i)X2;}jKcur zI}=A8p{3tY?XDfT-)DZpP!iQFJl+qvm@Bs@#L2GU++Tz$*J)pl8;2gts>6cmD^FZb zb={?Zk*T~*65c{V)Kwg;M5bYux|SP>Mvmd$UG7j*XH!b=f~s(G;B#w+cx??#BfsFv zrAp%@5B>+fF?X(4hF#SB%roaH}bBgX$QF2Xe!H0j0Y|8CcBS7&cnVq`@`7wN`e2IjE zSKRI+3rb?5Znyl78TyS>54d{@^30Wy0kcyocNW7q%|w9JKf8xL!z?<@TBwG$E-W&( zqf#1=ltmWar|ee^1j`zOYhoVdRMAAeg}42bkDT^6>L`9mllrVCJQRty9WJt+WmK63 z>ia9VO+O_~v~Z|uZv=vV*9>GF)q+_60A_uLJRX;<^%6LSYWN5Hgg;aEW6O)|{{RkR z%DDuqSbVLY{;*ok`N^0$896Qf9mn|of6enGSV6`GsnU$|oISSz5X`mX+ZwzV9F_$C z00I}l#z-89%qv_U3Kyaw$o{DWC%a6wBw z&q9n|DpVm=rm^`t5K+7ICefrz1*=vC#Az0Oa(8Gv-92MrXlgB^=@K>jgb38xz(GXZ zc<$=TvsmJC0$%W=++hC9Qgsx+CE`G6T5`rd4ND+{N z_&VTo0t|AODID-Q{5&P*Sy@?E@YUi)z%LbLSx+TlRHqGIF4iL=n@1VM1bB-nU^8dr zp~Sawb&YTtlK6d0Tud20MXoA~rQ?ZUT}g4ylOi=Vg(YSKN&~0G9Pg6lh=+3l0Jy|j z4@w`qHryLd-e4)QI**YsEWC}hnUi~#F$91Y7XwzwLHkqS=H`$By{xqbR5R+PalHuF zA4cccaPDKI1@k}RP@skTyb@_G?Y3gdvMg5^yT^d6Z+f2>VpFKRYNc-xPl?Xo1ot%@F9%o<^&=APImM z4FW!62K<3Z73Pf0zHB;<$!lTmBP+fPL*E5#g9ve^QJ&hJ%Q~6wP7EAuM$Z_2(z)*8 zbv$IuVTrV)8x6q!0NjWI07sa>AME`pYo=oz%R&TLgMbE63XKB|aI|$6Il6{rLF}Rz zl}s|YV=_vADqJVZTGRunOe&@#5yS#uV=yT&jH86V6{hcEUN4tXrM*gtTmoDs5i}T8 zQlaWlMX;F@snHD~V(EvhO~KPU`Xz;hAgTy-Si74m%EPN^Lql6TV9!Px#K75npjH)s za5&kC6-qQ-Aq@9QI-glU)Oo7oeCUePVbd4kOQ&&Bzl7|sh;MTfx-8iC1?$`SGuROl z$qsAeF-`5jTLTlq4X=?U($__&yOBDv1NEYivf6@8&C4kCP81Zsd{VWy5Zk8;Di2lh zI~UP8!Grpkwd#juT~tbK^e~1$seEpx^3p|YWv$aQ1}l!-2PWY*xk`w%Q2xQ%8Iq!6 z8^Ut#&+I8r)PrQXD8G0V5H9K)R!Ei)k+L_$IbJU3Zd%OrSj!@m+*R~LL%;t3EIXgg z>HI+3`B)f#F`U7{!_OB6&NI}scpNyLCbM2AfT-ZHs5lEo$#bGx5w55g*__08z~&XN z#CLzQE`M}~l;yMdZYtxeiA&Th`LQeU3T|a&COnw1;6k3uc5^JS@nbrS##M6*B5?{H z72+N_upLSW*xXHX&mb?`J5>j=iI7{t$?|n0nVAK*TsDUSA>B^|;I19Pe+UwFmv+y? z!3Zz^0Qk%X4jW*2hHfg=1xVbc8?B2lsOEgc-XEuP49MnX57e;uVB@IHACWaR7TcZg zNaBVgrY@o=VlYOg29?OlssNuR0|!woL9ISg?_UMNMlf#&6}-4 z(W$!BUS_H}TyCXdLO=-Iu0?Z6`;pJYC%m955Gh~btt~yF{2qVBuyAjS;Q{0&B_PD9 zTq=($;l}W@$~j;}&SDHL6-8}6LsK&B$wW-XsM}1Kq=O8~ZCpzc8bG^%*~%D}xBEd| z{{UdoRpwbAq`kuCvrB1QN`s;wAQ`UWjoO)DVHbS*BbZ%S_E|Sr2Vy34ltW9@7+j^c zlMZcq%gowvm?KEPct%I~LzPu!lw5}FpIc%uFm0)I8+i)wl?Mms0i6cCOv%q_dm9h5 zxISiY33EB_5+{jp#CLIP>?n?1Lu#|^3T*KYVJPo4ECnrZ*+@eK!zqZmo6gsS#1{sc znvlcif@oQVV!|t^LE56J?QmpOm=*n~xu(`Y0T9Yq85@sC(*S1XFU~Z>HnQu;1RQ6$ zk3t(u{pj?e`cAYlwE=B`xB(g2{Np+*%Jn1VYGIZZDbWuSvr*9+(c}xN4A$QGw71@L+mi9D(Nyn z_RVzqhgQ=W2*d`&=xLcozdNF&9^<4ECNOv?sAWeE++bwaIPLAhNP$pn!+dG#45pm zkVkb^z-e&D^?d&TZ~p+;a7{c4cqLkKawwW{r!x=K@Q9it=~D847kcRtx0%RkHvT4S zmi#p1NN@iDfj8mT8cVKKoHgJa1{BMmcoLXx;jF2^3C5EelnQqHc z)l{=PT>%J>VjT(f5i7}*Pq1K}(uLCQWOHcOdS+l_=OZlTH?Z;bJ8<+$0BIs^lrW_m z%)lckaCAv5I{6fD9f*(}OYpbbhqzc+7B&9>__<%~RlTs|AEu%h?~<}aR$PT`wpn+Q zSZ~-=2Nql&Ld4B(V1p@Q1X}lyGlbekS!PxeRKF%GfDAjA+-tal*q~!js~1a+WCV6! zbE0byJ8_mSF==#!{F74S*s{LC%J}Zs64LJsRjD1eOe>}vVSXknaN#g4N-D4-PLglR z8Rtgx4hEpi5X$5^nwm!c0Prl#IAQ0l{{RS5TFSYR#3=G|#j?2CUvA}acLPbergsHd zowwp;a#1Q(YIY!hWxd+z8IlVLgmLEQnp%|J%QJ<+h^%du#1Zz4anu2daS9w@z-%_= z?O3FW-s@hINJNWnuu?eNd4DC*N6FNJ69O5E-SUj6P9Tc|u`fYzU`u}l-Qox+On%BR z9YT*R;fI}nlq;^Kjm0*e31Uw4q*A6nI3_{8afi8TQKp#rj8&d5H{43AdGP6t34dzt zc2JV`VswxTU+D{sDgwq(e6v`Jt)f)H7+H|DZ zr{<#80kM@^9mf;t17$%UQyE;X1pbUx@U34CGbJ;+hW8BE%d{Kz6_$h-*(Fy|Mq%r$ zLk7_w0`5Q8E{1lsGh7+3CMU5UEb~T#n9ceZEnEu)&oMdQsaxSbCK@hZlQ7H`0TiOr z?li7Y34F&6T*r?jz~I;LSrjGk+PvFygmLF8_*^$KzI~A8IJW1RiCq#imt;lr4=SaL zg@S5;SGNQtx8sQ=<_LyLH!sQd5fa0q;GvUHROqQtJ;x5s+zr!FtKo#Uvhf0n#UFDt z+Mw-RB#!94gs{fleDVkPoT=F-!>EIf>l)ciDJzXgzEn(72I~eI-~Rv%#*3ip<(Lns zGRH&vh{5>~7%_s!cYI3m^kU$I*}}4cgHel?t3*sr;w2QV^wjb){3RPYtUrP}r z1uietxWi~|9T-eN@ZiD6AfST|3|!Gf3;qGV75o9O<_51qD}BCSl_BXDcCx{R3`{Sx1^8TwvKT-2kkxMqJXM707? zdnJOmoXIe6?kZ!jGr>9ik`M`rSlq3=da=tHkG7N{051FmswK73qQC*45J-z-80+;L@FtkrfE)nODo}o zP>oqaD*Hr>Ry2w$q6xpk3X!H~dqZ#ilt{ArqbjdX;eF<3kmy1}u$e7VoJ?l6kgJpG zU{`Y&wX8)7zxd~+QN2Po%TM@B^#KsZ(W-_8MA{i*85Vv~Nq`_Py3~x%&B&jZ$r6X=cKUk>#7JR zNz|oWc1FsVQOY!CB_#z{bM#{+oiM`;3u^Grm>VIgKNyx-XqehN zqX4-d_)j4;sC7D;g&0?}MeFqhKiJ};3ZEslfR~G1!*5pt$i!6QV$7_^txbGF<-@c_ z3b4D4fu1r9{{TQHq2ewLyD#DaXhnw{H?g^o1?IRq^(e5 zr?}C|i96h%>eKht6=DVb2_hqESF2JPflneF7h@k&vSQUaLdYx@~u6xGMR%xj4qnU|uy zh?)js&gq$vO`s6~tUn_vYbI(c7hAd>&LdS9h~ZHTOEi!o3n_bq(+$~C?%XNq5wBou zlmVCRfK;Ix;Zr{8x3aee)3|vzTy+^01}|^qI+Ud}_mwCJGtn|&qjQBo*AB#O95t%y zAYPNLDSxtckp{L^3;zJ$AOG3_3;xNlDUo^(LC2gLI$HChD+u~?6K)kBZIj#F=l-W#GZJ()QLYvBE3ImF?AgvwzJd; z^ZE{qGI$3iZNM$Rf-u?wQly{=Swk<)k@o2^=DUv)Fqe(DzeIr}_(lf%Fa<`yx=+R0 z<3?K4+_23D4tIQ7*cKTi;$$JEk@bM zli&A$7^4v>2>}@}N@g>)et}2M5#@CVs-97=i$&$wVvN6)?l!FeupP4v*ajn zJdMgEXk$Y_Tr%o`$FajK^Dl>y^mOR!ETL@m;B^^nxD<#?1EnC15&2^W4TlR(f2dJ? zT54P}>{{tjYrV{A&G3Q&(3_nx4_z>7CgXt6*-H$48Gn|g)?sKuOKnlV_Lzu#Em*gw zp8$JCBKU`rVJBVda4C216D}N&J8a=E^F7YaV5h`3+M-U#&aqku{)a3JU(UNP-M@eS zv&>$8jX%T5z8x-;p;6|5N~U5|L_~jR#>4sHl~9-Rm%IJ3W90pmlNMCa%>Jjf7&?4t z&Z%*+hEE=!O-GzVB00tghp{w7+~iMeLC)LtBvJC9^r|e1VLK)UScr;z39e!huYYTZ zO)YYK6iBt2pD8e-(MJ8f+lCyR}XcBUl_C01-=F)tWZJjBO(s)?~$6LGW} z0Wtk&`nMy{EQyUHL-P%QriX8ytTy92Mlm*C%H;ZIjh&wHA&;U?V$^8C+-t$_i!l-G zrQe`Lc||*+1$;j!3W^&-WH>VH7d{kVjk=Rn1A2)cz`lg#zoF|Puw>GU&1xN;@AD$( z)`htBs>CqgR)PP3FKbaaxA_S>j-js4#jyhoU}9eS(~N@&H;7LX(+8iZLb{_zE;fPQ z%_<)D50GK4&TxNgoFiqS`U zCMAO~VdKa90<6CQHq%H1<6_Zr%8?{7& z4JAk1Ec0eB@%Z4PS%XKer{1;ZigP0v@hkI?3%cNOWCGgjEQ>3pl+}-)uZgcXHA?`~ zR%qHyz$Jr~OtdN&t5;s&edbx{SQUqE@2ku(+>&t+*n5+iepvq5$Ojvb-UqKt&^&+mqele2!8}8QiD^g1 zAFp(Hqdo2Et>dMoTxDWJ>1TX&dTla9H?;xC^RIT7Zz+ zyFP=nkPe#{$0K-YD`ngW09^&jwi)fw%lY?3^RjVzkB*`Hla95bqIJReIB z?Dp_Yv>YSR#8p7X!j7d9Bm8{Y3Du7vG2305#csurB~r64zZrbE^gf+w z-$i?6pNiTK$eT(IcD36npr>S>n{Z+(#Y{eV2)7lRP?D{Ldg((7U&du@vgnS!0bl1z zh5aUBdH=_hiaS&dpFZI)Iq^1^;(mWMah&m{HaP9SI9}wPiT33D}GDM zLVLt1Nti7nTZU|WzH^=_lmqv{iKZayX-R?m#=`j!<1P4n5OGGO86~Fd?{*iR$h>n6OdFE)$FV9_M2-o0{e&aN^Yvtk=un0Hb0x^` zv^r7Wv0~i~f-<3ys8s4DdB@Nfx&w;JvL&cllS|NNY)}VN9P=*^y@ul@pB4oZu~KRb z#`Lxr^1VOiqr`%M0bS5Vje}P9b=`@F3FiW9-t(&>-i?^rooP~?rtZfAHbe{Yu#P7cHXlbF;5G19n(pI>oK6?~xT@_uL{85Cj zSL(AK=%RmoS@RXcvE{Z-r&D9{RD<03)T|%OnRvqlPnatX#PtF`FEEO_*UiH5%?fbQ zci~Qi^sH=&5QMy5@f6cYX-|=gicc4V;r(36?mu$@Yj}o6g*J-cT$}VdN>=-37Z0f7 z8r5eHtm)+h?0aTop+wzyG={>cEfaKE=gQrl|K$9s+miUWb^3YjwY2qh1u5mT&V-V$ zg>kKq--d!h-r*D0gJ7N`Eis` z?X;^*cTK5D3k;RL=elN77hpA@W!=I@&lg+hsHtaXJgTgbCPNz9!iDlW0&X0odxo^65AP;T;YGL z78K;bwiXpkFQTG*2sChf26Xm?m2O}DlM#L~+c@-#^3pfZ!JPOFwY-FzN1Ef*sMgo1 zPs?)50i@64HCHa0CG&llVQ)V6LAa^bBHl%ne*WDT7@JY=1`Z{VO!W}t9n2NbN{|Hl zBLT4YgWdI&h=kFmO?)PQAfQgqE=XzvE!e`A z3&n@Zy!_MjL&Gwp+TOj2N)x4I*XWnJ@BnvXRT5Dv`nF|b>#IEb%x@%o{!$6R8oEo! z?XjLiBQ##qBk>`G8sGLV;6ygRdb_I*Q()*E)uOA~&qZO}OWj;6@1*zqXq*2Q3}d#*nvNvF_9jSV2u@t zZ2e7V`w%mgKcB>L!&>Z3C0aJtR_hTKt7`m*4xeh?d|3%Xj?eT>eRdk}`pZMdx^wY! z=AD-_>+QaHG-5QN;4vaf@tKrG&WR^)l&WF&9o+@XF*VbY7rh}?E;`*{kP;+rAc>`Y z{w{KU=S>>}rhBGcd6v!eOW=mX(aG=AlVeru;RwI#m5h7;&$|8r|K*7)0{8E^TY+Am-((9pLd%Xi1!qONey(Q7 z+Z1)gobql1s2(OH98o%~zeE5E7W>`cy&qwq`ICjDB=+VSiGLBq!mdBO$u8XET77bPm7>S3&13`tFa;7qXdSD6xIa2d0@-pGnCQCy?0f zBco)C(~7gfpur@{Y7>=3z@F@{6Kb840}C_NSO9)F2n?~unzW&fC0n%S%V;2nR&Ek@ z&&2q-ky=Ca*FO};tJg`2j#$0LNyg?`pYdqOk0suI)PKl3HDT++tgN{n_fgGm6 zGkq6wW&T| zVId0($NeB0$+1J4MrFlG)X$8QTi`MJtXZ3TIZ;-Idv^>gKawYBBiZ_3ut-7%Kw?7x zI9OJOQIkDKoPg)kRean6_$98A;5QqVTKm|s6gS`Z83Mom18Dpv2)AyX)+a^0)wOxo zj-BMApeQ9X6ahF2#v^_kOD}u;G$O6C$1%y+^RanoxzE#nj|z`7f74%}{fy|`O!CkO zxkIvtiYin$Gy!yNg;cRaDFJYNA-seId&9dM^%D=dn9nVbZcQpSL4EYE6>>wJnIJ)q z)o#C*uPsAK&l!A5oqmQ#E(%1~Nt)}FX4P!j> zKb2q1K2{Z<$!)j#II(sE|JGkWZN&b9sc<}jQ(C7M0l{tCNt^bM3$2>>ZU0ec7o zy6rUNdW-5VYq6&{|6Eerr~B}Ds-d4;7E1t^Z~wNo#^rOB(nN-L%Jt-r+%Taog_3_tYg6MijKv2V12 z4aftEoN!rH(kUkdynvjHW<52PySLtB`?UXn|A6&cE*X4)6nPMm@yIJl{k&zs z#a+22Ae~Hg|8E+PjR_Pv3?^3s$YB7Wp=rKx>GaC0in%|$?f&yT6P5s}2-TvjW)?XJ zdFSiQKD)p!X^%SH%`ezAi@B~B)MZsCoFiOPI^MA{iaGvd*F6=wEHZ=OAfdLN( z*BXh>`LjpY<6h=PMtRb1%2;dze9AC>>%mYr4)q#yFH@*eI6yW5rNPI9upY z9d=taH+uUf>9yxn!!|ZrG~!hxU(fSQfE0joqM1>FuZ4Wya{I^|r@FU)Cof;K;lKx@ zRIHFaP)#yE61+4w^!(aGzA}7@=TufCnjAOxZ5e{Q2+lKmX<*DHrLyspTsJK@ZvX4q0&tRlrQ&kn^UqOb zBIK%no_X^~5Bs?yT%jO11Z}`9y9E7ZTy1Uk@*rT*A}+aat)-56s* za@1lH4MJ8VD|QF_{6`Wc&R#~=X_5>P%|wbC0KfnQW?f^0lZNd{+c3=ZuKJF7m?0mL z5_hd3csDLQdRK<0gn(a_r95}AO@Cu@aP4?cG%i|V*>kdR!U_xmprlbitS04(@%GH| z^zJaG`ycUg$b>nro-Wf~R3TAEx^MAv2GLmFx@nGR;0WH~R>p`!&HJc?=mHcLlpG&Q zj?GToJg?dmeDtf~Y})*jpSjU@8oV5;3dl%Ew??>%3u?DG;sK*7DbD#C;8raKqt*4W zGe|KmAQT1x!OSe@cq?Wx#TRAY#0;Yb0JZEGN%`X4+Lo!D# zQZW3;2dkK)-0~$Fa-OPd0tMkyhROh;%3xGtYRQo}_tzE~2Yu2cY)Iq2csf3%)8FQ^ zZwT9JYEZdzh`@4eNu8!-*^yB0N!^#B5+pVo5{`q!f`yVMvV5zy?YNb!?zD(@HcKG0 zo)ckmsp(b66n2h!J^8XO;_}qmCg<~0ro~T0^t`{WI)niNIWw6wL$wT2*+9hau?L|O z@873lS^9ZsQmRC~aLeILM~tAjJ>3sSCuK{G%xVorKlbU>Zg)MMMnW5mO(ehtLjf$1 zl1=GA#eYElk~5LeVBw1enR~|@{z^m-b*4N0X0}0WB9_;Imuz>fsOb3OkD%$p5=F%+YPb>CI$Z(+A!%zhIyBM}CZFBSj=^~{CmVgpxt~jQ7 z%jB?2p31#7%nE!rvepBf9JiQ^Q%&L|#$Cv5(IYP~N)sENJh$J2&t-bIJjIy^;)a;DDz}s%ut1nyZ74q6UE|oa zs&1rdIcp@mVF(P8VLS}-fthFASR{Kqaa$pea{Fz=ubZPUq$K9a(V$e=BK3}42x8Ms zzT`Z{r4DF_G~A`RwBpRamU;BQ2 zc9tTF{4L(SM2>~3eOMGT68@;Pg-M|FkFm|te}L1h;g*n*CL1#B*=sY|c4`v7PeWp) zhe=GH;Xc}G$x!JXd(vnr48mH(*x_8N zP|^k4nCoJe!Q;SRjEXq!hH}q-|Hzr>80&17sImD;Bc@YW`8yDoEvbKU=#gM&KS+AU z!*<@VGtJ2QY>JFzN2>>;h;n9QRq6`1Qi<%)wmhyMb`tRKev+LqY}o1uiE`?fKNZQq zJ80&9D3_=D>WxTzy@lewqIq{OF^a-cr8L%eb>v zk;4x7;4boFJNJWo7FO4Ojn8^R!mZN^Eryfu9}pD07VC)ecLnfC_P{2AU{R{()vP7; z%=Grrtm4cNu?kql^UzC$eol|slt!}G#D)P=>^ANKOu8?IE z?-J?SGQm=GFQ_g|m&Md{c9T=BlgKkDe+}g6wja7DVY~zauVIm{YQO16Nt_M##X)7Z z0app+$!vQ>5OJ*;rpQ?h@6M(>u@IBx%kk zOFpcA<8-2a@SxE5XDPn(VTbJY?<*FcvveDKLX;M?W`u2D&-r!$Y(9Vy!?ij6w4F42z(S5100)u+G32|k$B z5f#GhL*wygJzP@slw4idh|wh>9|mA#-XG;t2?n<9rP|B>1G4z*x()`{?w6E&-rO2_ zJ??9!4{L;7%A>XEkNC_>QY$+F>cLJRiy|2JtV$?U#mMFzTRorauGL)l<)wm@Eym_C zii!1{`P6YwquU0Dd^bj|nv8O@dz<#Y=MbJ3qp%+0-2ZhX)bEbd_Y4*haMhg7_P4raof@aWvb@TM z9LVL;a5@aymqy9y{HjHh{{!X%FYo#8e0F%Ggj(d;@U23%l#qx=Qy09nEW|1FbwLiC zOp6TNCt%%Of&GAQuGm+KZ}NMNJylm4GC6V9D=8g^z+>p$OoOh5D?_BStD*u*S;g!neT4cXe$SN!1CbitbE}t-f7mNpNrs&I!JgmvpeZ?Ty>$sbQ-IM!VANgF z(s?}MQdfG9xdW39yIg(w{@xLF$Lb;#XUXw4M@9x|90~Ec>~Sz_N0@TGRs)5hszZ~; z%goZhD1}K~IRz)7R~J(|ejl~39k#NqP**b!qQVSh^IUM1yCHl+b4v-oUDEJ%;Uq&R z{7ANpX*W}np+tnS#VpraJo=_Iu?@Gu#O2{(El*D6_E+DnkisOH%((G9CZ+YD3;18KKB<0q*sGsUM&}|sr8e-L=4T~!DN9Km5w_)jbRc)^zT0_(e}4uVM*fCz1v<}MLc#Ui2USzJ0WCbA$+=d zh+!k##<6UDB>e@T1S|6;754fa(m$MD?tL`g_x0z9m}uDMBfUqexc=5hFJxc~CU3|Z z-hwoQFS%0fW?N>kIEYHE(nKAFPz^bMG6?%C#wnE#MLQ7hTug>urxWX+4*69sLuRtF zT?Bx@d71g0{~0tUN@+f&mTViZSE{3i7xtO+8bZ@ZJ*fF_BuRPmy;%`nWGFEqEgdZ$ zJ`Um7&5WWqfu*qcwq|T9I>(3q9ijHH*PSgND8I~(>bQ|~-{sq-JyR}>I6v@;O&j-g z^CWX_yttxR2uYp5{o9{7`+fIQtdVtLorj_U$=dCd-ko$Kz52v+Uge8dD#6_@PnvU^ zgU4b+jHHd8%u5{Pq-8{XTGQWU`ip%7KVDIjMin#gmuM*2wk-uqJ$m$!nJT5YKsGqa z(2m7Vjr84%ITC!oV0VziFqCg7UTCx~zf599{z=jY!fF!Z{Zn1b3;mrD;!FSF?H;DO zxr+>AlmWr(r93Y_E!-HnGcz}hVi7F(y5FJ02^H@DB5&r$2l9iz_+^ESQ_F z@b^@3P{T}Eb;O!{Z{jjs++_j>Rr-4WDgh1B9F+broH$3>Mp}Y2t=F_dLLzbW!ei@> zbFy=zuus>7GrZUK{nr>a@8XjVJT|MOt*^ zX1zmSTG~t=f|J%4NgaizP9I}DSUBD9l-t2(5{GPY+$4zLlMCkj!bDbp|7<d-a#}CQ0}APLWVCB@sml%!4peChOMu_HuBfH`E*mFh&@T8* zN_%%u6a~N+rwZ{32-Z5V2_0kEf2DLSN>BXL&Yu8?132X={Rj0{Q!&HN*mG(`L= z6j11D@$41hd;K>nNIo`fX=;-}FtFb7A_wazO3t<=or(8$q%D*1UI+4Q4&%VKm;SAq zf1r!Gkazi}tUKH8+QmZ-Wm9FuNbSppHj?MFh z6SmWTOJ~IM1RUL16D`696oc9_HN26$#D*fZ9&$(Ac%NmGHf(Naa8;LKR~Dp z@+lg^cjmn6D(@Qd0TVuXa~XmAB;}J5PFSUbE9bJ#BG8>WimeKg5&IeY`nDR?uW#-(lG;vBRX?^YwkI?~^1c9l);wWmc71 z_h{eMx6zmux(c>Oo!gyObC%cX*L$gZ>`YuQ3V%K8&sytWot)A9>y89Dc*Zj6ay##nH&e*adGRoTUrtjyFN z3uR@HPVuXeY0a2$pQi}U6#=P$x^|7mS3n%H2FYj7y2d6TGmLARm#TC0F^c|RW7!F5 zM2mx>yvB31VDvB*wfTts$7Y%TcVxcRV2Avh6N{Q42YjUgP1JX@Yzn9VbvNF})q!FG zvImFfB#ew7z0XqW?ccjro}JA8nJjB{^ouw44)o#71}{6kyTR-HQoYNYAoLz4jN^ik+=pcnkb($24-)OI;O5sA=2CuqJBW`j{BS)EB);R>O8cm=e4 zt`%Fb5q^}%HY1NyYyCZI!z~@td+vzI5Dyo=Y4nxe$*(QyXL6HBs6G2@8#BWj7}W)K zj@4VPKMLx3TwlQMtQO{r_z=yd=-;@Tq$>By(sUW-!~X$22EmtaxXm*79@Qatqf^2O zB!j)EhW1za`Cjb;Lj&x7{{fbEpIn$^bJ&T0!VNNFJDyRp2Z~S*&DOk7!pGyeR=*5% z!Ye>O95j?d((ne8qA<3Y&|_TZ_WTo`oubAKcSrKNwHRV~CRj=U<@MYIrpQ|{CAK-G z0uKyorClD>Ci1>Mv%Y^R60MX8awj@0<6yDJCk=OUOACDPD(Ezs5rI*pNVy8`I=l*E z{c25*rQrvN7Hs;)qg`BVZ5>}SayQglk;@2RfSL3~dPbM3w$9+2FUMoEil$@Cecxex zeaqp1T=ep${W5+KycC|>}7)p1W;nfc#$Ot+#Qt|YC|hE~}Si(! zAsGNU+oBEol-h7k1(@P__sT;VmOXIIM`Qg}oRBHWlik-6mtt5pkT1H;92lE(ANe^< zb1ILfoL*k8GQ}hT?=z@9>c+{oi=9jGw}5Z_mRti*ZfD61EIVDT zP4B7p>=Hi4Jtji-1XRdCm!ys?&leAku0HCNoEfgYvt*gqdYlcP$srVSpOP<})+gyE z=cs z^yJAqmn@{+IcNMK8F}E{@(QuyfQSl`D?yO}1f^7h65$k6q5=Eg3`c44vX>~fR1Kup z)YgJiQv1hddua{qaO1;1i@fqTQB!EvjqB7uQDnnp50Loeil_6W#M2&}qPxwAYV_yL znR9>ZGOSJ!>P~*z?Wt2bgXpZe09%6hO>^2LO_JubUfl?!41^pGMk#?(umFUNlc4N^ zY*(yz`6Wg;HIgcYbCZsQ@}u7V=~YrN`Bb30;i7*3?M|O>=YN1aEdd`2A2VVw0E1{F zARyooTaOA~`sLv(x(0QoG)=AWkDT(=t{h~6$Ntux9jdR4SFKok2Qn#JhiD9C(Bv>E z5`!$80hsL?3eGHn+)YB5!(f-AnqCg_Fc(nFjFaFXg;2^n2aKkxG{3?d5v>Em3P>6~f^_ig=3lX|jdl52$_v!rH z6Sr#6`Aa1%iLqZ*jW9ULAafQ=d}MaFJ%9rLKMW5CgD{XMJ^)gOmS#CMdfqzZ@dC~D zYb4vF@?=Y2pNa}2h(3oWeIq2h`!xps`#Fj)4hKhY5o&=!@d-E(ico+60I;?&g(_pZ z;ZUs25ve=CiVz$yGy8tz%t5vr^3{$+#^Ina;6vGXwZ5a5L>^`o%B zqAtCRFOR}7rv)5kM-uj}&XL)`!m|LWcw)hlM9OG9lL!&8e z+@Jd<);QQ)tNy0BDj-*2zmt(#azY~(fcP~Gfp2bA2!Z1*YuZUr)O4rw;qj#6msa0? zAaU{TKj6Ffso9q4hJ}x4QC8F6Z}9-|%d8wy_rIJ87laSqs$}U5b_ZL1%si-`$uRTdTYokjv=Vq^< zNGu>E8j6yE@L@ao|4e1@{10#xW?b96`FEkb;Wtl9IPy+%RFac`@jm})bFHPyv~&WJ z2~Rv(4ixdABGg0YDvGgx=rg3tiTT2=_y11KX&&%br*AHsTwV`u$Y9yX1pSiqV|fBc zymeK^M-Ei74>*GhQ#YzFDmIfu332~7*%Zl~D{t}-4weEtdf$652i%W15_EpUxmK9@ z*ZHiOOZ2+m8#6`#h^8RS!k~Phy_69@dWlz({}j7j<(>L9It!A`EzI`4>mr z1|?5uN?o3i*+~;-Mv5*QsZea0Xxoi#ASLazUz`ZlHDuchn$ckVKnSNwl0;$Xd-hP= zt~-NO4d=N&!P?2>6miqaYD-y}!oG8*6&*stos#`+T;_wTvRfBAxurm8BpyHjMF16; z>i5Sh4_i*Bn0{MQyn(w%FI+D4Ys$u}&lRGDidH3j%*39*XOg4}FaOFBvOAc6{zqz2 zqjX`*48XjY8fO3PUEHZ|zmP^BVfe*uUKDJ6b60~ZMx*1=36>ut!{4)(`yp184dZge z^LaB*=^`oAJYxgm;ZM*ZY(hr#Ro;w+E5{C-D=+ycJGQP)7F%=T=+gY1gEq@8`>ag< z;pYu0E@q@jjk7(xC|atsZ%J;ZzFeOpW-sRyM11S5Lh+68h-3s1OCJE@?YD^ z?a3*{V9G`d>C*sPbEwKF+kzvR1zVCG32xup_2=(Jw40ieC=!2f{(yf%S^)&$hI&l1 zsq(e$pAT!)x6745j|-QO1D1_e3ohtqCK@mt9BjTXh^d~tz(uI3=F|S;bClbib20&R z3LgPLQqmkB-{l|PWgC2LyA8yh{y=o<$JG6~PCDSr4~jB7E#pu2_|3y&x6jUFor6@d zO%_MTzGlg=W0Fg7AQWYEKa0g!=|gcJ82EgTseIj=hqY`1REWFNu6$MHBiiJP5)e?1 z18nhv9d=DFXB|%0&*8%J5R5T{DExgdC)aOsqoj=j&n4c+Sii<|Tviv6+s&P2CGRxD zA+bIMSC~`x^^3_yYTR1;)wDo<2B8nR7-;$a0&hq>5oO(M^iUBs zLlM)YD%q`RbmOjbwCm>hsD@hCBr`N^orU|^40`nh^c~~yG2C0hrtx;8vGHSurt9(_ zWD88?5muVMnh~?gwRH$Qf@l5&n~JVPtn@S~|4v|IW&R(U9~!b%yFr);^QhwP(i#09 z5Qr;o%>GdPy34jBYYtl_LX5IGAQOLXjw$0?@mcCcT>l?9ofwDwvzl~Lr-aO-ex9Gl zP=NDORhz@?(k+AdUXe4``h$rF`OUc zttjh<9R)BE}P#5Rw#JM)VG69X>0Twwd!n(%n;#sSB!$&3&D3^uzm3>evd0^Tl-S49-Q!4%;(T;ac7+Y<0NUqmE_ChGx#7~()hrk3 zxt_%BX&D0g{CzX4T{Wpf0&o^nHPhAQto6x1OU=@na`F;f`A{`+s>OveD4BFV3JT`V zx(mF=DB@2ojn5s_ls|FFV9I`S*Aj`C!>B$n{ULjN!?a0)TW?Z0Qp?GpmHkDPR)upP zrSczujyBy)_i!;hKUp5xDCYXwDJ3J=OY*Vnodb5!yQw|CC)73Sr0lM!4VHsz3M_mb{`lFs4hyN_f{8&+Y8vgq z6I*k=M_Mt`ZJ9((Q2fDBDwGpC+mRK6uO6Ay-*){dyg=PFvgu!}DeX5T-My-p7~$=- z*;fPtp8S|PJtaqxCGGDAMkY;n-Ev(12aHSusA>Bofxf=IPC{uNsJGZ^9pT2W$ToUJZ2MhLara%27RGyBrf+dCs?lQ-{*=I%BiXKdIPJP zyH@VBX->hazkOY2ru?6m6op4lvlqlJP1`LTUQ}4bePwlK_I(o0;PtUi)<4EbTXHbg zFKgt_3H4~4>qIIyddW#}?pqLgvCCOzVuJ9fz(Vr3my2LydZ48NF(xNm*QGKfFKCoB zKD=%LIN8lO1)3bDc=^}nVJ!I*=H}Au$*Qk&S_kS5s4b`e0Pg9o%Zq=Ep0Q}Yr_Ck) z-r+m?piz1X>pc?ac!+9=8gpY;qkV?nx@PbhdV1{4!(6y=?JeIU1c<|b*LrMxaY%tT z;R35ZxYvLT{qj5xi}@}rEKKR}(N}Xa<2%22v z*qyraFo@x;LolXtUlQJ+eQrR;O2s(w7sur{xf-)t;>07f&ZGBSK%Bq5Q`35vE04`m z&b(D;BSTZrLE7zyVYRPKPR>C~E`QQ72UwRji}}^pE1#iD@SRO>69k*=+f?_f>Td2hp5=^9}@iz3tog{sS72B_G_^9F==>C&jHL$@N06 zYdU5LwLU-VDGY$%AVDM2yH$6KCWuy&Q{nK%rK68k?QyxEnsZ7sQPlyY+`pL|Bjkdc z9B#Iju_iZo?UV?yNxbJX;uvTJOivQGhgeu>wlXfiKYrqouoQgkRNC0ZwwPvy4~~+x zXSzw?QYq%-$-q%uLVm^kKrA(A2#WmO!3r%(<ZySLT$GKhTxdA^g_m9)=mYmBK&NL z#B|@P>VHcN&epi*bnQeumVfytFW{b!y);{}9m*>yyQZ}jxPNUf;=+G;F%4rT;35X`zKT68K^Oj9)o4*Kc`JoCQ9OphOYP!E!jeJ_970L}#cZ1`)>f*)*GDbwv%Qw2 zjHX-?&L!O1fgyH;&MeJrl_SVM=QAQ^g~O^t2&$&pa=+)!mX_Lr90W87_y`yj+4C3e~e4o1yGizsXBgU1=e zEVuX5L>Lg~@XHPuvRU&Mf`G9jp4m4nhJC>R#B?>1!~(hz6AnA(oQbxRC_-B1@FFd<725Q?L&r>dI_hRUoD6aHJ*>Bw5-)6o|ZjcJ8gMQ z`u|wcqzo$*^=6wx#Zu9zRxmZV`SE~b`R8;IVNG@Zi`hw0Fw9B((Y{Zwx6#S?T7c5( zpOf3WyH>_-FoxTd1wcy{l>_$U)pvL|%j$=7UKuL-s$KB;sZ;1IrClik|MdfGWLQ{O z05<0Be;@yU0g#b0@ykH8_{?E$wINA`J(`%>Nqj8Kcce+b4Y+xVoYbhf+kU<@vb8+T zwHnZqrp9nRa%mvhL{s4}W0&eY`U=f^0*wfAGU=u`?|kG9kql{{!P7k4jLi(i3IS;5 zDW!gT5gaqpUrPjcuh+!{C>^%rxwfcZ4|Azl_>x$nWw>M%2i|%?N!MGc@2D~pY|+-74?`C`{ny| zn|uoq=s$CO1W8aJls^j}Olm*}v^QYY22m|p>`xFG4=b^R`Q`GXZyB~S5;pB37I?3g z=+c5rzlrtvm`oR%-sKBfP+MTfcLYF{1}Fv_~M=p z>b*Tv3NRviiqvp(NmKNC`9(e2tA5^jN^F-UQQ;*^Zr$>mxzmnkrQ&pN9F_U{8}#_q z{fOC$`IoxMzSv|Ku+_Y1e)xea=PeYbvXYB(owyZo^y?chm02II&50oPb()&*Xj}al z4{l`n;ge{#g;x{h?U->VC3-%-QVL(9Zq8=Z>`VW?n>Xu*YP-L| zZ$f`MoP4qN5*IaOvTPTC zF5wo&VSqqM(Rv=fMfoFx%FI;4yd+52YZ@&dJB`Rsdo|REDn$FR{`9A3j&m;g$8dYC zA$mTs9fG`3zS$6~9M|)XLl1URIi@)g(E)7tCoow{b1`o952<_&=g(=R&;}SFtBu74 z#3Y0-BS5mbmpc2_@q}=hB2=Q^Ax$NGq}ElSuEulSa1TNU8sWMTmT7|nOe%`aS*@bf zdNVI`(Om!i9L!?>_OKdR{yv$9Z!@ay4}9QB(g?UVOl| z`f*BY{I-3MOIG)eM|%z6gnRLc2nEGv*P9)%NqIdDSrd1mDDZ!LyCxwvAHjZq0CKuPK`e`TKVWA*7*?#x+qbm72(NqZcv^6C^Qw8|FM!yU^-y zzE6b`KvrvS{Y7i_d)1!cq}!Afk34ctNKdli{z9Z?>G{|@D`dUr?A>Q!?ilshcZ-*@ ze&%eKE{Ae|Y0$?0omd`cH2 zBqqe-yzXhaQt~mND=q0Fcbmh>3aSFc>~H=J~QOjAnNM8QK>)#8OVPD>iW_l~P`beiK0$dMY9Y7z6eGIFSh zZDY43z!2R0+$7S{+Pu`3HqC!JA76jSSNKP5-{^9(KmIIH^rw)ec*q4*`h{J%0~1Ym z5r==~7geH$>@d)#{96X=9}dOWIQ2r~X=wf^5>#ByR@H*~0DSe5AylE}$hz##RMc1Q zY_G6pddt@&Ks|SR^p}I9(NcVyRqg6QnvsE!)g?DpMNKl?{VR&4oK-sc7139AaK1nk zzmTPctmIacwlhY;#tA)o#A`uJqEJ$ z%&?|HtNqNsG~@HU$`Y)&2DD>-4NV;;N5EK=NwjQb)Jx$nII;AJ_PXx* zwu8)7i;l8FN;V1Thva&a{{WF;jgD6L56NH16q46?e#F;&U<&@}V|9v=i-^uYxI?5Q+nR-_Z88cv!BvlLOUZt5!rn@8yX&DVHDmKSY}Een!4vAV$iMq)_D-vYqER(}ex?%5ch@lK z@MJj03w#gx}U}MtFL}SFM{R_^kHHe3Ax32UH<~;;H39Yr3ICZA9`lYB8ha z`R6?Giw~*|dmrmPd&N0ZKW#2--~Cpv`ws{&ZdrYqt6#JF9z62Jy7zcQYkP)PwuvcH zgYDTr(et6HzYB{*)rox*Jel;htv;7EPF=#`?4QAp>Uh@eV_O&-TQX|D9i&)Y+$ee7 zX5)M`;ZOHqGdNeyNV_!*$+h`ZxJS0WBkm5i!R3g^djrX5GpZMdlVcDXr+1_YzG;Dr5{CMA!DG6G@=^3R3oeaP!{%!Z5_j zHzsN&dZ^Nu?xG5+8jlx##@QD>DrLE8*iqrFH2yw`{apnh1*}oa)%Pe^6zRR>&)3^B9N`+sc?< zY?=6KLOxudnF%Fpv#O6%D9L)6rL@ai9V%E<1Yf~L9~3FhgSZFrV;rflo&Jxdv+!zT z{k}d{q&T!lae|a@aaugM7HiABxH}~{BtW3J6^AxJu>v(N76OEl0L2MjoDf`!1$XV6 z-&*gi`2%Lw%rkSIbN2ph&yv-b<0u`Hmsi9MC)|oLWMS#xsKu%JSe+?PtNz^B z_HzL;ZxDWN`v%mKO-r)lnVC{wN|#EP1;dTCS`!-Vu7PQ2mJ}I06gfzKEnXMN?9-F6 zW9}Ts+O~l2SBiEhI#by_MHIpHD5!F3hzq}H=eiHZ-W?@uiJbt*O&=mlbbTJ{qXMLOHV0!r=x=>wW zJFd@l3#5@*;CP+jS3g@Be3z=2>3TQ&T{H_PElUPUN=*?f35f`hvM6qs9momGbsV&v z@nE_smTa0VW>x-J?^1Y^iVrqeiS3H$pUoh0-I*j6#dq#`=<@iK&E~veW3ZeYu5`X} zzj59PZ2eXCk5ut++x)km^o;PKKmBuIt85O~Ac4-^V;RN7!!?p^j2EnT{dEaL^3r%X z%|lI5tRhQN@~!{cU!od0Lt!7y7f-D8z(`(k6v`caY_X1pphqx6{wt$3fuV=R7C0HS zvdoU9dnJWNN9UU_z$S70b2paG5eVdM&Bw6((X;|vX&Mv9SAK2iX6k#nSFlgZ%*aj{+-1bVRkLvOOUo*tG zczILLnkP6Z!kv>ce1;HiS__#Cu6rT}6)f}KNlB`Q{#8^RI-QCQ-8*Cc{CZu%ITu+A ze4b3+q+j1c0 zQe6F`uq7Il8Ht^}a z*&rehD*l|Tl=Ac@sC(PmQSn3KzGj7{z%L1+OuSk!McsSsJf*Kgy+hU$AxQyRbOLn+ z*<%jbe`S7KD$yqMbr*TA(9k-fgH15cl{Qe0B@Y%1%9$e8b19WIhnu`6VV_q#_BD>n zzWukK*46t7$$o}Xr2lCq=wP*V-Q=xAVu&Z$XtvgR(jly+L{$Y~rd`Vswy)JMQAvDj z?=vS{2ZMcDn6H*pjTDXwmk;>PB;pHXb#qEyIg&JU{F8738%0P5Yri?QMPHC0IafbC!mm4{t|Igs-CG#O!-1U za=pJ>J)X_Kgow_qnp3Ut!j*sA;2U z*Hb~R{oJwiMri#pj5AHAJFX{Q#)*cJPOVPtgrnTOabhERa(ju1y=nH-pi~~IoVDhm z$4=)dr%*cAY_FS|-?Nd|n%-81Cm*@et^OF)7&Vi7q?E~X)o**q@6}$330EAw%(TnZ ze3}vHaYepkl$Rw-R>w^vUt;>(0P4bJc|abdZDXp^0e6vRemg00P!G&EaG53Ngn#J3 z?w4P=vHqyLYrw1YRNLTD;cbr-7`MKGil?1r&5_mwnt?QPp!bc&fuLf8LOZq|@@U_h$@YIbv-0FfHsNi#*-If9F&y=& z13quUdi+z;$e>pJ{Jh-p%!@KoZzMM@Zo8orPumo{V?F2B+PFismbuqLZ86mlibUG| zA;gICm8853*qdkQeqhbu(YGG94hm+wwYS;p_9S5s@%ZhND?c26AF_%{p6Hti!}@nT zRBWT2R~fk7!(si}23|;N>-qqtAsX>%P?;bL9gKpK(!Bj7;Rd?p}saAKnWib1L zVq$QFlg9lJAZ72CZ?Wj5wlOLeAKmcVDn)xpDCdS@VGf5@oGg*KU3-!cbF1uvShmi(g7P_xEiu0~b z9_GYE&{ZEU#^;KOY2|;S%Ut7{hWp(pSWUH<-6^q<<3uDuNqcTPE~yh#{GF;hMOFn% zcMSNk$6ZxSuqJ+O7Dv^Y3{2tgYb949ASQf5d$y@+-FGU^8x#r_$^daVzL=beY>!@; z_CC;Ka|{zh;V%X2#-5cso*P+Ms%7pXiZQjWRb1W|a{`zLOdf4ti6Atj%~P@rJI^K@ zqJ-DkT-uV{Z26KildMd_2lh<)$j{zpet2-qQ1T{7bkV+-Uv{Qag71WXOCTSw&(=+L z#Ih>kCzN{*Uu&vcU*y}4jc#Q~bWN=lgNN8N9rEvORJ>rcoTb;RsVDcBuWkYyt620w9Us%t!E&WdcIg1#eMilHCHn`D-}dr_bo6K zP165fnsXe>h&QI5p`eB?GFGqd;YOhPo5UJ|97$_|C5?ZM!tNZC#~z)V<3J6P&-iKJ zSDh}^(k5S9zCB-HFPF?T`Cn+zaCWwJ8E=3+2?bS@t86yZo$0r2%~*uigzQ^~(%5eg zhuOnfYqXV#b0aA+enLS)qY^f?8`OQgp`9+WxNfcLRWGrxJEp!ZYdc|Nhcc(=>kJ+H zeyOhWFs$u)z(85ULS(vzurr;(nEKgtx z?NxzKQ9>8APGkwT%E>^&v`tyzRdCSR{^9x-ncB$SXVEsHkmM~Lnvg&B-h(wg3saMy z2x!4NW{m*HUU{j~0zta?(}kIFsuZ=Lx_ZvmfEMyAzV3fh+EZL8F*WO>PMv~GkbbQ< zj|)%rw+gTLw%JS98jp8p5}USLCzH&z5F!-l(s@p7MDDRrjNmrq&Zq4R!T<89nTV@X zem<((6~69D1-%e3CA0{>8b>8U|RW*&$Z9WfBD-tT%Gwo^0T>xRLJG z4L((It^~Ca0qIr;5l;+Yu56DMptK&dYFyD(vpT87S+gr^B+16R{inax_#!K!n9$T- zb}Y8L2$^I?D^cYSe%ozYqyXyo7mMKo+K#qC0p8eapmj+ece;*Q?nSKFQvZRY%jV|mN zViZlNA8o{M>QlUoWh7w*eUs3>%~kObJibUxDeWYay2|vAMM$DZ3Q?}mQIjQav{pp= z2YL&}>`F;%FWRMH-W~0eXXU(#VpFjp;;F0g$TZ}m-?ABn3?>4}l#~BXNo@lwXrM_3 zK!ns?$N31w@FrRT0FOTQ^7qZH*_6grxC%i%7P7bm;_jzq<&3AVM_+*0*k}u!v`O7krn`4BZ|XH4JBe3^6Rc%18hS}*DfK5a?*fiW>bD2rE$ z0W~;+pxjly*}p^sL3|zLzB#-()PrbBdKYPi-d>swOTHb!ocXuY+%FN_3W?22{2fKY zv&9HryEvj9+#bwUIniUWK-z1JAGFtHHlA znBktCp~})I1La`nMhCwz+k(*lv0A=8DRumb9_;2Gtm_?HNXH>Z&grX56=>HDwWF4@ z#Y#Bb1W&-09%larCuFKeSAe|2Vg21bI8FJ)$p=N{g-z)IP?=z(>&J?rtDcLGJHD*i z&FLrAv5`HetN4#wsJ0m=$y^^qSf}n8YC~aLIswSq1?GUt50!4lZQ%ey%yCBm<+_Ea zzeFvn_mpk2=?g7kixR2{3S@jJ!83+^d~n~S-xb#t^D9H6O>QG)KYW7Dv7Am{>Q7^a zp55fpMLcekhl%m+W~Iyg&^B#5EOkLUD-m1S%*0X*kEzppofvp2c*e`-;hhvGHFQSY zJJY{mZOGb81c)UA(+6h3`yb6ntZ*6uL92ma&Q0g{Bg-@_rt&DuT`F^bS~x-b#p)b= zz>`!EB4-2^S%}!fr`|{RQK&%$1Oc$aXD~>YA;RjCqJ5 z9r`J|9kw+0(7Hr+w3`w-qB|3K4yrH~S?K^GXTD{IrCjw+6pUKMV&v-Skj zY&wnqWBer}4->~eOqjVd7;|OXiOMj6qsFyB#v)v-!9=nJuCE50JLbUEdaJB4%E*JX z)uH~*1m7ob>3&1)o@d@Q95qtH*ha^#B@iqeyg7=2(4#Ocwn@JV>}O&oI}(_Busbg~ zVqEj8iZlm-s~lxj$o&za zpar-Z$&=8`f0(PfSmOc)gWh+zQ-;t0CDA@dypHYG4Gw-R(D)oD*DTRxp(R0_t=4yh zD=Q(#NqIm$)=zZ0+NA|qwZ_&T_R;=-4<^C=m8n36k1J1fb5Czx1v{5ZnEfR>nn}V2 zw{*2x?et+ItpAZLL6Cp`fuW#E`}0z7$Gd)qHf7-llPqm4A4q>J7^JdtQDO;Vf2D&9 zwv_44TK2&lv%UjyYcE2@-1@|4wOev!BW1W`-~cD}xlAQsyOD@YS@!@hse!j*#v6Co zkuY_Du}eY+j)ksR(xzw_F!$6B5s<9dWE8$lk~=_8;+u>TYwe*8M#$f-+)CaPyWD7V z7#Pc2yz3n~+3SR^05w1huLbj4Z<~{4k0Z)q(k>jn`?H-|Mqb_llsgY@S<-X=ah_gG zrWKNi@W+eC9dKT(!5G-)i|kgFL0A}!j@9k))B-GUt%aK)Uk?0PCR^~D$E?a{MCPt^ z@z6R8t+|&tD9j&MKE?XZHXlZ<6qkEjo5iD6%=00ow`1X#>(?s(!R{+%WvL~g4KGdc zry)6#&fcd-%;x;0s`Bw22T9Jtp88|a8(zlT|8BPpvoCesD=iT9lrvNCsk}F%q28(cV3E9)RzI!DzGz;8nL$@4 z%J%Q`j|AEn;lwI|t~C+9^pM(-qo%Q-_&Sb`Ukxt)CcAWB&FnVHj5)YzvuKyOACY$u zS3Xi8eHt?|<9@!V9j&Cay2xhd-oLWVb$-zzBG5Gtc_CNGWPMt|ht$u?ZyfYxdZFLV zz8K8|0B!Q6<(;}Eg{Q4Cmh*rTxSeRaJ0#!% zAHMX(swV}QF1NWs*AN+h==cqbd{(r8ihetN-s`_8seUJm1lm#}?z}z&>o?LM> zP#s8QIn1L{+sNo(bVC0Lf`eyNVqmKO@O2F#5 z0sVuKuox?VZoI_>L=CG;8;Zc||I452oi7|KzcbG`?r10J@`9m@R^SSiR`id)9iC+u zs*fIbyk`6X2A*sWZVxE09ONCiZ_1U>8F;~(-o0K!7h#>D6hshs zwwtlWaze!roUdqY!lTK735*PM%Tpq=$VV}l)&H@AauGjm6HDjArgZNp>$u>4thnTx zak9`XExtffljT&BYv2z6kd@~Tk_*D~bq#KWmAsW#*ne>faVXU~4I2BMLH3XJcFEzQ z+Tag4`gB9YS?Ps3k(Y<1n3O3vzDxI~I=mC~f?MtQFwY=}V8f=sa0<(?=F@*&q9l>V ze1PX84cOSvCgTi3i?hB{9F}f&Z;3N*b}J)H)_nb=;-pvmXfkZ|N%0&S59o&kQWF=s z49P9@1fK@=1|i0KmTk?{P7$H(E?oM$2-P2n2EW*t+a#}kea#WbwNKHzcsOoYAWM~` zIrUiw#(`ybuMg)zToyX{w=4Be1ZPk>)2s2_DZ<8u;Xo5R{Xb!}XT9P`!hoY5&?3=N zpNIS?+*rkOGQ*@?x19S;Qv(9V7tY?o&8zLTuAUR9yQlkctzxV`+>=@J^qH}p5^;33fz)eRQFw_>Ue(`a@d%lmZJSB zQNBt$Vt$GFVDrVKFznT2SDZ`}FGwXP$ujJH$3>F3_`36VlfbG)4v~?=95*_8 zB!1(NViP-&Tp?$mvZf>$dHj5xy${>eY&!&Ao9Yx;-LCJc_epwBo+IN=xiat0Y;^yV ztB=QMzV5wk7mYm42*TZL(#fb`xMG#=`;SBX*LRrlg&Fy2Kj;V5pAy$?apv9y7R)-D z)b;#IKMQ%TS7bsZ?&_1AVI#>W1^Uvt^Lb~ADnb!IiKywJbvfBO&p(mVI%C$A*8(0% zx365-l4aYO5F}}rxv;xAMR?|-aK`KIyrrHoO1+cajc5JO(KR0z$KqCqA9fe#qv*4k z)U4`@PIbNU#f}^ULA%M}{>nYm!D29oVMoU6qH0t?g(cvb56H*Ga1SBW^^uoL^MuzG zmxx#dxqv^gdp5;y#y|!DA>!AwAhjYIa9hk&+#o^o-klhs587XFlz4*)W-S*?ZeX%_ zIeA~f0-E)?{YlXJ)kr_j@F2oKsSZ=g$EbzGp5J6mdMWxKyh0d8Xs1#&sz^q5BFI*> zTXEXWa?MTXe*IS^j-(q=20n}nzWVw8E=3Cg|HiS=eHjI1J}C6DKl`=ovWH&FRJxGC z|MG+*qJfZXYdyIck>AI9-k!MufUkS2mUF6Yx1yfWyd5-uh{Ac9=$4f~cq=)wq?iy} z=|$Lw=eUB;?|n$OAM-l9HQk8Pd%ViNAULH{27~Or&zPXNm2=7~sH>}TPOVn0?;X(8&cjzddI9!Q$Pa5@H3(jC%uc`eS736gGTR?q&a1%;WF`DG5$wCUaqG(qcy-9Yl zS_-gvOoOtBMV8?$E83Jd^zC>TU~w8!-xD7#j_w+*jx()vEZtMqyApv2)BWjQYbQS6 zQ$RbeNhdOlx?-B9(3Ii#=x{$|kxbrh_g&ae)aChm=?jS=I!4q=5&p-f;hUZRP@|3~ zsm}V4b81~!_iw(sbnrQ+w(TZW>h|o{F_ya}t>szCYde~7haN@bQ?-M-|KNw-Ke+na zGsc{5p_>-e)eB>38DK8nye;p=`w#|MRlt@Y=q!jfYsZJI7A2sdDp>RhpHHJc>nr5) zDGrMiw?Mn}cMCo2XzrHXWoy$FuJ7p(WTZXl`36=hR`7$8h!t>?OZRr#W`B)#pVTod z5KHi1d=!$Zc_d|&7u#|B8Jn{67avN;FT{&N3a=<9&3Mdk-tG~xzU#s+PVzR2IfzBeCHS48 z6hu#mNfZS2L8@`LPX+ac*9!;6{S!dOnPKwAO%@=myyDGcM?Rk@9?nI zXy2#x$q>DJZ5u;-7Vwkg@5kdfzry-=ycQ*7B7IxI*&Jy=#4bO>OiZ|9t%VfN* z9iSr2RR812F3?|kf>D{hw?Bl#;hWvN{D<^>tD)822jE9k(Gk=Q8IFhsT}CxDGMKkZ zG^%yso4TQltN+bUiR>0%!Ghfonz}jN&@HsOQ$)r+98xh$s)3hZW93bLS_HE)_Qi`A9Iv?eGF?145QxLihV{+zMlV&N>Pp^78u;dR1pCq=Ul! z(xZH$WiH>FV+Wh8FGoPeM6BQ1cQje@{5zzu%MQ54gZEpbCq}9kHS;$YBHK>~&O=7U zw+syk;h^gi^$hksO;GlW)V(os?LVd?pQ{(VrkHl7Keh!NP;v0Ff)j8G5Xwa5+nWEW7GkZwiAN& zvVAL!&nG20kPgxteSObg2Rk}^IUo?3UtZm&&n~hM)v$c0@lvP;kDwM^&ZkB$TOK)| zlSO5Q(!ni5p2$aCg}tg8OH6zfUVe#TgOP6(P@=TBWTHe>2(%i%5*c6XZ$otJR#uTP z3yoj{$2s{j7TTP;v)FTyx|_?`(Vx#T40Dk_Uq)SkE=fxZ)aP#%2l{t}H8j`pj8~7# z%r^*ywwAWLUvV86!ltAf$e36l>?-r4C1RkNx=N(Be6rXie8BdtOGkMsgZv;!5Vu*rWs-$-AEhb@m zgFn{?xx1*#`}Ke2qzE1h-HY-ql>B;CD0vXwW+iRfWB#T#eC6ZmK*O&KB8?|7Rf)^q z@Ki<1)U5f7`~r>|4sMi43sdLKX;b~udOyK3CB@v!yWRB>`_%j{ z{yT;a?g;3v|F%C^Nd;iFoejyjEV{PfBx12<@N=dXF*l^v)NIH27Aj!zd}-7J`V=O8 zt;OMyYY@ra^gr$`Gy}K_#de`ralFCpuHM0SzV^$3=k1u~i4RnZ02Z2b;iRRyf+cP` zFdrv!T$7suWFGxJ)Y5P`Uo&a+u2>-mvD#I%22ShLaU>yomGaF0(*rXjL}IBY>JeR) zH1z%cj!S!t+V(9`KZMjO!lYG9+E)9^ZGQATt(R z_`=mW`x0zesQ5uI@}>(c__=}PhUEG8tR?RaE{m*rxIx2HI}Q8FKNj?Qvx+|Xj>VbB zeu2+SYh9wfJSp7dBwpv8vuen7P$=cjVJ9y0xt6pHYNT2=cCqxxkUx*>+Y+oR*uQsL z9(Qk{KkNCVZyu{}+12r$E60J{ujA6DWhz)Z1qRZe#15nL`L@Gnxr@Ui3p%yH=Bz=r zxyMU`>?Qbj--v^uO1qO!{_Q=sq()K%JWf__EugP_WPicP=_KtiKEn{Jz-b-0w^zA_ z)}vxZ1nn;pW!10Cijr=F>noVG3?@?r4um?+TseI0aFaVPgK4)|9GX5H9=yVqO~jmA zGN;ai9M5+R5vr9fCqahkv1lu8^YCIJ#+IMN8TbpGprEh=TcL zU+oj+V7;+2J1@M;3qjLd{t%i)yXLJXw?3J&d0yF!a!29XHCJ{j9b>nVZ*dHL;)rtO z7sFBQdBbRcjFC^O!OV?PfZ~-@;iko>lvb<3z*2$QSFMe176Zq$Z9_iU?k79`^Zc5OC|QEBW9KyrE6XWV~ZOO&@VHI~Cl#}_eJ*{-$izGD*` z9ckvNtJy?dD>%_YO7$R5RFrkFIU}2^IvG>kuPH*GJ>H*WCoEk1tiHh4$zFiR(5={u zN1-*c?)m!8oz3Z=-q51_CpG$X6cyiIuuV+1a!a+0!sJhHo8)Aq^>1#RoITEPF9K@nUPRYA!Z<^u8>MhUg_F>G}e5|)5YQ>VBNNaxNgA+jtXtcmE zf9w)voLn;L;XT)%zJ)iK;|N`PTyJP$QZ z{~)Ig^xUOK?TdDk<^Ogt1?`G;+x3nOP8LrLZ<@3uSpE?!o$y|EW}<$MZzZmc?DzU6-5Q&0bsk)e#KCs&Iq;Ox1fTHQ$y@gJxU z*)G~>frt#YxvIceDZJ{rJ;4+umn7pjGX6w;-WEW+q)v`T&nB_{llale@M%k-FK2oM zIEJfr-CE8D!k)jxaYdMRtfosdHiN^}9QH9;Y8>Q-Ym-pXkhKC996}S}H^>2T$+35T z${GJ~eww)5!^JdMV1KEX-4H2M_P<~DBrYW2D~&mf@zDn zXuS+05I1g@-KP`}*Mv#LeMXH)Z_}othZDBTzLMa~2oGbj~&Z+|_mX>9TH zqEkzxgI4T7lIz^OS(c6E*;iQAYQK{8+7;6#CaEr(uIEQ~q3a^2`mXrNo`cR-Mk{^^ z92d&qGD}x5|D&osRC<5j_!6~HbBJK#;#u1*u?e?r@f^o_D;ND?5n|s06wBa9 z+~#-Fszei}HD)uu9W90Yc-pEI^e7geBc!%J|!u3g{e|EE0LE5Uu+xtc& z6@_qaqm@-U2kvmo6?*@;@EGm{d_G$B%H~y%AOyFuyQ8-e;Bp zIEK4f1MLmdD9o`D7-h=@ea^T2;|HZrlcXlh#E+x_AZfeIUQ6+$;W+N^K;8=ankvTE zUC`((S%WW3%OCPtKEf7sf{Z%I7@m0+I?cvPPHcOs2(DVmKoD`FpZx!c>Vsi+1hJQYQY<_wAyK=-aXGAB#!p{^`V zfNWuGF{$24CibEO!jlB?1ho=2`~(JN+}Vb&4J`v%mTajQO#>KGVG07aJHToDmT1!0 zVOIK&OQVc;ln%ECf&?{{KEBFw(ygieB`F^@ovFxS2g1b?L!5VdG}Bb#79Voy+HG3i zmi*hCa~5PNFT&yJ&qsnv_WvK0^;M@}(m+z&((}6!HSCnfG&ZY`jPgRDfU(qrYU_1- z?uS0oX%I>{no*KA9reN6P8Q=?!4({sNUfoBMy>^VHB5r+z8&+LFJekoBR0d~S3G77Z{3ObnUhr4jkfpJfc~3UDNhmRuL~^7GQm%7 zJKYpibm#`3TArfNvJjO=soEIYC9Z}1NdCcD6=PV@xA+t){vhhNV|GUx_jNt=DQ2Zh z)74ggiToWjgbO949-b?mv#>kQpUS1wdG0emwaBi)u8QVcih}ICU(gRs{A9LoSEl;0 zLjlUU@mO^gPx6_|!NBQ`6zhcyM||n3zh^q^JO4y{?eu(6Xy^y<>~k@#9~3r!b$Yqr zI{uE;o3= zu2{*6D$5py6#E~27W-ix+sqigz!2v;?rfp*bG5bXTc}6-uMI~b_O35gL8+#eu_Yaw zXZI9;iD);Is-#qU6m!-$lqlpYOP@a~t^YRo;{6=s>=O;pvQh2L+eoY}>;bD1X~Byh z!{MKFCqFcO-$?t>4(b&l1VFH-KI8##j0bbwX~qca822sushl8u|J3t;@RV4dn}w+d zWnT2rxlhe?1%*5|jIA_1rq^o_4#9dS*YB#o_DRt3oUHvNI)igP9+Hnh&eQAbj22MC zQk;yz7cXh4Lwok|pTjgy2(jp~k#dhhiS(2>+4@*HXGEzC%~k&$E!;dKKruqs-ix_x zBW)xhMaR3K_b0(>&b(XJidn7|kmxdMA)F3Vz1x;xV-&Nm&*Jm$I%hDWyDobYqOK0T z!XfFYq^C0pyYULndSxgDjXJnKAdrwnr~(R9?W zl3o~eTV^DU)ZhZO>s-#{-||%zwOF)E(tBA&*XS)VpAUpbvz7%jF{XUw4~iq{>}cb;eFecv(fa3!xQGGFT5Y5ULdn7wmP5OPQj*^)3Qlq-u(e1bQWn3hzK7%v&V?#Xdiq@ztr&{lz_DP>v zC$K^8@hX`HizffA7`+|xr47`NEFPDQ~+u>u2Pj`=#2z~PfD zVSg`SBYw*MSz&U0$vwI&xpA)H-@>a$hzowFz~-|Ms&RUafUw-7^ldminV-Ux!dxFt zx2DL;jXx5T``{w&(|c;Y)q4hQhr=C3#B2qWc!xBDQQpwpgD($F6pI3mWqx11HE}oo zhOR4udkfs9%&V`EN(F}`stN$R3pH-sculTUlh6@u952NCs|)7An7z+N&@7kGx94^^ zI=M(gIQ-V}{|;gM?R`D^CUe3t4RP>mHDd~9BFC%J9$vJ~etym7=#G11_jsh53mYR4 zoNGwmtP5*3c$KJJWaKkrC%_g%Kzb5y{HmZP|5wiQ#ngB7*EPe{x0@=>Cm}6eGt7hU z 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%0AkS8~A4sxc0l1vVF8R?wS;b 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